More C++ Refactors
This commit is contained in:
parent
58a6706cf9
commit
57503d6a31
@ -62,6 +62,13 @@ string(CONCAT COMPILE_FLAGS_SETUP
|
||||
# Skip RPath
|
||||
"set(CMAKE_SKIP_BUILD_RPATH TRUE)"
|
||||
)
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
string(CONCAT COMPILE_FLAGS_SETUP
|
||||
"${COMPILE_FLAGS_SETUP}\n"
|
||||
# Disable C++11 String ABI
|
||||
"add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0)"
|
||||
)
|
||||
endif()
|
||||
cmake_language(EVAL CODE "${COMPILE_FLAGS_SETUP}")
|
||||
|
||||
# Fast Math
|
||||
@ -79,7 +86,7 @@ if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Buld Dependencies
|
||||
# Build Dependencies
|
||||
add_subdirectory(dependencies)
|
||||
|
||||
# Build libreborn
|
||||
@ -117,10 +124,10 @@ endif()
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
install(EXPORT sdk DESTINATION "${MCPI_SDK_DIR}" FILE "sdk-targets.cmake" EXPORT_LINK_INTERFACE_LIBRARIES)
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/sdk.cmake"
|
||||
# Sanity Check
|
||||
"${ARM_SANITY_CHECK}\n"
|
||||
# Compile Flags
|
||||
"${COMPILE_FLAGS_SETUP}\n"
|
||||
# Snaity Check
|
||||
"${ARM_SANITY_CHECK}\n"
|
||||
# Log
|
||||
"message(STATUS \"Using Reborn SDK v${MCPI_VERSION}\")\n"
|
||||
# Include Targets
|
||||
|
@ -2,12 +2,15 @@ project(launcher)
|
||||
|
||||
# Launcher
|
||||
add_executable(launcher
|
||||
src/bootstrap.cpp
|
||||
src/patchelf.cpp
|
||||
src/util.cpp
|
||||
src/crash-report.cpp
|
||||
src/sdk.cpp
|
||||
src/mods.cpp
|
||||
src/bootstrap/bootstrap.cpp
|
||||
src/bootstrap/mods.cpp
|
||||
src/bootstrap/assets.cpp
|
||||
src/bootstrap/patchelf.cpp
|
||||
src/bootstrap/debug.cpp
|
||||
src/util/util.cpp
|
||||
src/util/sdk.cpp
|
||||
src/logger/logger.cpp
|
||||
src/logger/crash-report.cpp
|
||||
src/options/parser.cpp
|
||||
src/main.cpp
|
||||
src/client/configuration.cpp
|
||||
@ -19,6 +22,8 @@ target_link_libraries(launcher reborn-util LIB_LIEF trampoline-headers)
|
||||
# RPath
|
||||
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native")
|
||||
target_link_options(launcher PRIVATE "LINKER:--disable-new-dtags")
|
||||
# Files
|
||||
target_compile_definitions(launcher PRIVATE _FILE_OFFSET_BITS=64)
|
||||
|
||||
# Install
|
||||
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
|
||||
|
@ -1,190 +0,0 @@
|
||||
#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
|
||||
const char *arch =
|
||||
#ifdef __x86_64__
|
||||
"AMD64"
|
||||
#elif defined(__aarch64__)
|
||||
"ARM64"
|
||||
#elif defined(__arm__)
|
||||
"ARM32"
|
||||
#else
|
||||
"Unknown"
|
||||
#endif
|
||||
;
|
||||
DEBUG("Reborn Target Architecture: %s", arch);
|
||||
}
|
||||
|
||||
// Bootstrap
|
||||
void bootstrap(const options_t &options) {
|
||||
// Debug Information
|
||||
print_debug_information();
|
||||
|
||||
// Check Page Size
|
||||
long page_size = sysconf(_SC_PAGESIZE);
|
||||
if (page_size != REQUIRED_PAGE_SIZE) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Get Binary Directory
|
||||
const std::string binary_directory = get_binary_directory();
|
||||
DEBUG("Binary Directory: %s", binary_directory.c_str());
|
||||
|
||||
// Copy SDK
|
||||
if (!reborn_is_server()) {
|
||||
copy_sdk(binary_directory, true);
|
||||
}
|
||||
|
||||
// Set MCPI_REBORN_ASSETS_PATH
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
// Resolve Binary Path & Set MCPI_DIRECTORY
|
||||
std::string original_game_binary;
|
||||
std::string game_binary;
|
||||
{
|
||||
// Log
|
||||
DEBUG("Resolving File Paths...");
|
||||
|
||||
// Resolve Full Binary Path
|
||||
const std::string full_path = binary_directory + ("/" MCPI_BINARY);
|
||||
original_game_binary = safe_realpath(full_path);
|
||||
const char *custom_binary = getenv(MCPI_BINARY_ENV);
|
||||
if (custom_binary != nullptr) {
|
||||
game_binary = safe_realpath(custom_binary);
|
||||
} else {
|
||||
game_binary = original_game_binary;
|
||||
}
|
||||
}
|
||||
|
||||
// Configure Preloaded Objects
|
||||
std::vector<std::string> mcpi_ld_preload;
|
||||
{
|
||||
// Log
|
||||
DEBUG("Locating Mods...");
|
||||
|
||||
// ARM Components
|
||||
mcpi_ld_preload = bootstrap_mods(binary_directory);
|
||||
}
|
||||
|
||||
// Configure Library Search Path
|
||||
std::vector<std::string> mcpi_ld_path;
|
||||
{
|
||||
// Log
|
||||
DEBUG("Setting Linker Search Paths...");
|
||||
|
||||
// Library Search Path For ARM Components
|
||||
{
|
||||
// Add ARM Library Directory
|
||||
mcpi_ld_path.push_back("lib/arm");
|
||||
|
||||
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
|
||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
mcpi_ld_path.push_back("sysroot/lib");
|
||||
mcpi_ld_path.push_back("sysroot/lib/arm-linux-gnueabihf");
|
||||
mcpi_ld_path.push_back("sysroot/usr/lib");
|
||||
mcpi_ld_path.push_back("sysroot/usr/lib/arm-linux-gnueabihf");
|
||||
#endif
|
||||
|
||||
// Fix Paths
|
||||
for (std::string &path : mcpi_ld_path) {
|
||||
path = binary_directory + '/' + path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fix MCPI Dependencies
|
||||
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
|
||||
{
|
||||
// Log
|
||||
DEBUG("Patching ELF...");
|
||||
|
||||
// Find Linker
|
||||
std::string linker = "/lib/ld-linux-armhf.so.3";
|
||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
// Use ARM Sysroot Linker
|
||||
linker = binary_directory + "/sysroot" + linker;
|
||||
#endif
|
||||
|
||||
// Patch
|
||||
patch_mcpi_elf_dependencies(game_binary, new_mcpi_exe_path, linker, mcpi_ld_path, mcpi_ld_preload);
|
||||
|
||||
// Verify
|
||||
if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Set MCPI_VANILLA_ASSETS_PATH
|
||||
{
|
||||
std::string assets_path = original_game_binary;
|
||||
chop_last_component(assets_path);
|
||||
assets_path += "/data";
|
||||
set_and_print_env(_MCPI_VANILLA_ASSETS_PATH_ENV, assets_path.c_str());
|
||||
}
|
||||
|
||||
// Start Game
|
||||
INFO("Starting Game...");
|
||||
|
||||
// Arguments
|
||||
std::vector<std::string> args;
|
||||
// Use Extra If Needed
|
||||
#ifdef MCPI_BUILD_RUNTIME
|
||||
args.push_back("runtime");
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "options/parser.h"
|
||||
|
||||
void bootstrap(const options_t &options);
|
||||
void copy_sdk(const std::string &binary_directory, bool log_with_debug);
|
||||
std::vector<std::string> bootstrap_mods(const std::string &binary_directory);
|
15
launcher/src/bootstrap/assets.cpp
Normal file
15
launcher/src/bootstrap/assets.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
#include "../util/util.h"
|
||||
|
||||
// Setup Asset Paths
|
||||
static void setup_path(const char *env_name, std::string assets_path) {
|
||||
chop_last_component(assets_path);
|
||||
assets_path += "/data";
|
||||
set_and_print_env(env_name, assets_path.c_str());
|
||||
}
|
||||
void bootstrap_assets(const std::string &original_game_binary) {
|
||||
setup_path(_MCPI_REBORN_ASSETS_PATH_ENV, safe_realpath("/proc/self/exe"));
|
||||
setup_path(_MCPI_VANILLA_ASSETS_PATH_ENV, original_game_binary);
|
||||
}
|
75
launcher/src/bootstrap/bootstrap.cpp
Normal file
75
launcher/src/bootstrap/bootstrap.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "../util/util.h"
|
||||
#include "bootstrap.h"
|
||||
|
||||
#define MCPI_BINARY "minecraft-pi"
|
||||
|
||||
#define REQUIRED_PAGE_SIZE 4096
|
||||
|
||||
// Bootstrap
|
||||
void bootstrap(const options_t &options) {
|
||||
// Debug Information
|
||||
print_debug_information();
|
||||
|
||||
// Check Page Size
|
||||
const long page_size = sysconf(_SC_PAGESIZE);
|
||||
if (page_size != REQUIRED_PAGE_SIZE) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Get Binary Directory
|
||||
const std::string binary_directory = get_binary_directory();
|
||||
DEBUG("Binary Directory: %s", binary_directory.c_str());
|
||||
|
||||
// Copy SDK
|
||||
if (!reborn_is_server()) {
|
||||
copy_sdk(binary_directory, true);
|
||||
}
|
||||
|
||||
// Resolve Binary Path
|
||||
DEBUG("Resolving File Paths...");
|
||||
std::string original_game_binary = binary_directory + ("/" MCPI_BINARY);
|
||||
original_game_binary = safe_realpath(original_game_binary);
|
||||
const char *custom_binary = getenv(MCPI_BINARY_ENV);
|
||||
const std::string game_binary = custom_binary ? safe_realpath(custom_binary) : original_game_binary;
|
||||
|
||||
// Configure Preloaded Objects
|
||||
DEBUG("Locating Mods...");
|
||||
const std::vector<std::string> mcpi_ld_preload = bootstrap_mods(binary_directory);
|
||||
|
||||
// Configure Library Search Path
|
||||
DEBUG("Setting Linker Search Paths...");
|
||||
const std::vector<std::string> mcpi_ld_path = get_ld_path(binary_directory);
|
||||
|
||||
// Assets
|
||||
DEBUG("Finding Assets...");
|
||||
bootstrap_assets(original_game_binary);
|
||||
|
||||
// Patch Binary
|
||||
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
|
||||
DEBUG("Patching ELF...");
|
||||
patch_mcpi_elf_dependencies(game_binary, new_mcpi_exe_path, get_new_linker(binary_directory), mcpi_ld_path, mcpi_ld_preload);
|
||||
|
||||
// Start Game
|
||||
INFO("Starting Game...");
|
||||
|
||||
// Arguments
|
||||
const std::vector<std::string> args {
|
||||
#ifdef MCPI_BUILD_RUNTIME
|
||||
"runtime",
|
||||
#endif
|
||||
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);
|
||||
}
|
20
launcher/src/bootstrap/bootstrap.h
Normal file
20
launcher/src/bootstrap/bootstrap.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../options/parser.h"
|
||||
|
||||
#define MCPI_PATCHED_DIR "/tmp/.minecraft-pi-patched"
|
||||
|
||||
void bootstrap(const options_t &options);
|
||||
// Debugging
|
||||
void print_debug_information();
|
||||
// Mods
|
||||
std::vector<std::string> bootstrap_mods(const std::string &binary_directory);
|
||||
// Assets
|
||||
void bootstrap_assets(const std::string &original_game_binary);
|
||||
// ELF
|
||||
std::string get_new_linker(const std::string &binary_directory);
|
||||
std::vector<std::string> get_ld_path(const std::string &binary_directory);
|
||||
void patch_mcpi_elf_dependencies(const std::string &original_path, char *new_path, const std::string &interpreter, const std::vector<std::string> &rpath, const std::vector<std::string> &mods);
|
43
launcher/src/bootstrap/debug.cpp
Normal file
43
launcher/src/bootstrap/debug.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
|
||||
// Debug Information
|
||||
static void run_debug_command(const char *const command[], const char *prefix) {
|
||||
int status = 0;
|
||||
const std::vector<unsigned char> *output = run_command(command, &status);
|
||||
if (!is_exit_status_success(status)) {
|
||||
ERR("Unable To Gather Debug Information");
|
||||
}
|
||||
std::string output_str = (const char *) output->data();
|
||||
delete output;
|
||||
// Trim
|
||||
const std::string::size_type length = output_str.length();
|
||||
if (length > 0 && output_str[length - 1] == '\n') {
|
||||
output_str.pop_back();
|
||||
}
|
||||
// Print
|
||||
DEBUG("%s: %s", prefix, output_str.c_str());
|
||||
}
|
||||
void print_debug_information() {
|
||||
// System Information
|
||||
constexpr const char *const command[] = {"uname", "-a", nullptr};
|
||||
run_debug_command(command, "System Information");
|
||||
|
||||
// Version
|
||||
DEBUG("Reborn Version: v%s", MCPI_VERSION);
|
||||
|
||||
// Architecture
|
||||
const char *arch =
|
||||
#ifdef __x86_64__
|
||||
"AMD64"
|
||||
#elif defined(__aarch64__)
|
||||
"ARM64"
|
||||
#elif defined(__arm__)
|
||||
"ARM32"
|
||||
#else
|
||||
"Unknown"
|
||||
#endif
|
||||
;
|
||||
DEBUG("Reborn Target Architecture: %s", arch);
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "patchelf.h"
|
||||
#include "bootstrap.h"
|
||||
|
||||
// Duplicate MCPI Executable Into /tmp
|
||||
static void duplicate_mcpi_executable(char *new_path) {
|
||||
@ -43,12 +43,10 @@ void patch_mcpi_elf_dependencies(const std::string &original_path, char *new_pat
|
||||
duplicate_mcpi_executable(new_path);
|
||||
|
||||
// Load Binary
|
||||
std::unique_ptr<LIEF::ELF::Binary> binary = LIEF::ELF::Parser::parse(original_path);
|
||||
const std::unique_ptr<LIEF::ELF::Binary> binary = LIEF::ELF::Parser::parse(original_path);
|
||||
|
||||
// Set Interpreter
|
||||
if (!interpreter.empty()) {
|
||||
binary->interpreter(interpreter);
|
||||
}
|
||||
binary->interpreter(interpreter);
|
||||
|
||||
// Remove Existing Needed Libraries
|
||||
std::vector<std::string> to_remove;
|
||||
@ -96,3 +94,34 @@ void patch_mcpi_elf_dependencies(const std::string &original_path, char *new_pat
|
||||
ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Linker
|
||||
std::string get_new_linker(const std::string &binary_directory) {
|
||||
std::string linker = "/lib/ld-linux-armhf.so.3";
|
||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
linker = binary_directory + "/sysroot" + linker;
|
||||
#else
|
||||
(void) binary_directory;
|
||||
#endif
|
||||
return linker;
|
||||
}
|
||||
std::vector<std::string> get_ld_path(const std::string &binary_directory) {
|
||||
std::vector<std::string> mcpi_ld_path = {
|
||||
// ARM Sysroot
|
||||
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
|
||||
"sysroot/lib",
|
||||
"sysroot/lib/arm-linux-gnueabihf",
|
||||
"sysroot/usr/lib",
|
||||
"sysroot/usr/lib/arm-linux-gnueabihf",
|
||||
#endif
|
||||
// Libraries
|
||||
"lib/arm"
|
||||
};
|
||||
// Fix Paths
|
||||
for (std::string &path : mcpi_ld_path) {
|
||||
path.insert(0, 1, '/');
|
||||
path.insert(0, binary_directory);
|
||||
}
|
||||
// Return
|
||||
return mcpi_ld_path;
|
||||
}
|
@ -7,11 +7,11 @@
|
||||
#define CACHE_VERSION 0
|
||||
|
||||
// Load Cache
|
||||
typedef struct {
|
||||
struct launcher_cache {
|
||||
std::string username;
|
||||
std::string render_distance;
|
||||
std::unordered_map<std::string, bool> feature_flags;
|
||||
} launcher_cache;
|
||||
};
|
||||
extern launcher_cache empty_cache;
|
||||
launcher_cache load_cache();
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "../util.h"
|
||||
#include "../util/util.h"
|
||||
#include "configuration.h"
|
||||
#include "cache.h"
|
||||
|
||||
@ -83,18 +83,16 @@ static void run_command_and_set_env(const char *env_name, const char *command[])
|
||||
reborn_check_display();
|
||||
// Run
|
||||
int return_code;
|
||||
char *output = run_command(command, &return_code, nullptr);
|
||||
if (output != nullptr) {
|
||||
// Trim
|
||||
const size_t length = strlen(output);
|
||||
if (output[length - 1] == '\n') {
|
||||
output[length - 1] = '\0';
|
||||
}
|
||||
// Set
|
||||
set_and_print_env(env_name, output);
|
||||
// Free
|
||||
free(output);
|
||||
const std::vector<unsigned char> *output = run_command(command, &return_code);
|
||||
std::string output_str = (const char *) output->data();
|
||||
delete output;
|
||||
// Trim
|
||||
const std::string::size_type length = output_str.length();
|
||||
if (length > 0 && output_str[length - 1] == '\n') {
|
||||
output_str.pop_back();
|
||||
}
|
||||
// Set
|
||||
set_and_print_env(env_name, output_str.c_str());
|
||||
// Check Return Code
|
||||
if (!is_exit_status_success(return_code)) {
|
||||
// Launch Interrupted
|
||||
@ -161,7 +159,7 @@ void configure_client(const options_t &options) {
|
||||
if (options.use_default) {
|
||||
// Use Default Feature Flags
|
||||
set_env_if_unset(MCPI_FEATURE_FLAGS_ENV, [&cache]() {
|
||||
std::string feature_flags = "";
|
||||
std::string feature_flags;
|
||||
load_available_feature_flags([&feature_flags, &cache](const std::string &flag) {
|
||||
bool value;
|
||||
// Strip Default Value
|
||||
|
@ -1,259 +0,0 @@
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <csignal>
|
||||
#include <poll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "crash-report.h"
|
||||
|
||||
// Show Crash Report Dialog
|
||||
#define DIALOG_TITLE "Crash Report"
|
||||
#define CRASH_REPORT_DIALOG_WIDTH "640"
|
||||
#define CRASH_REPORT_DIALOG_HEIGHT "480"
|
||||
static void show_report(const char *log_filename) {
|
||||
// Fork
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
// Child
|
||||
setsid();
|
||||
ALLOC_CHECK(freopen("/dev/null", "w", stdout));
|
||||
ALLOC_CHECK(freopen("/dev/null", "w", stderr));
|
||||
ALLOC_CHECK(freopen("/dev/null", "r", stdin));
|
||||
const char *command[] = {
|
||||
"zenity",
|
||||
"--title", DIALOG_TITLE,
|
||||
"--name", MCPI_APP_ID,
|
||||
"--width", CRASH_REPORT_DIALOG_WIDTH,
|
||||
"--height", CRASH_REPORT_DIALOG_HEIGHT,
|
||||
"--text-info",
|
||||
"--text", MCPI_APP_TITLE " has crashed!\n\nNeed help? Consider asking on the <a href=\"" MCPI_DISCORD_INVITE "\">Discord server</a>! <i>If you believe this is a problem with " MCPI_APP_TITLE " itself, please upload this crash report to the #bugs Discord channel.</i>",
|
||||
"--filename", log_filename,
|
||||
"--no-wrap",
|
||||
"--font", "Monospace",
|
||||
"--save-filename", MCPI_VARIANT_NAME "-crash-report.log",
|
||||
"--ok-label", "Exit",
|
||||
NULL
|
||||
};
|
||||
safe_execvpe(command, (const char *const *) environ);
|
||||
}
|
||||
}
|
||||
|
||||
// Exit Handler
|
||||
static pid_t child_pid = -1;
|
||||
static void exit_handler(__attribute__((unused)) int signal) {
|
||||
// Murder
|
||||
kill(child_pid, SIGTERM);
|
||||
}
|
||||
|
||||
// Log File
|
||||
static std::string log_filename;
|
||||
static int log_fd;
|
||||
static void setup_log_file() {
|
||||
// Get Log Directory
|
||||
const std::string home = std::string(getenv(_MCPI_HOME_ENV)) + get_home_subdirectory_for_game_data();
|
||||
ensure_directory(home.c_str());
|
||||
const std::string logs = home + "/logs";
|
||||
ensure_directory(logs.c_str());
|
||||
|
||||
// Get Timestamp
|
||||
time_t raw_time;
|
||||
time(&raw_time);
|
||||
const tm *time_info = localtime(&raw_time);
|
||||
char time[512];
|
||||
strftime(time, 512, "%Y-%m-%d", time_info);
|
||||
|
||||
// Get Log Filename
|
||||
std::string file;
|
||||
int num = 1;
|
||||
do {
|
||||
file = std::string(time) + '-' + std::to_string(num) + ".log";
|
||||
log_filename = logs + '/' + file;
|
||||
num++;
|
||||
} while (access(log_filename.c_str(), F_OK) != -1);
|
||||
|
||||
// Create latest.log Symlink
|
||||
const std::string latest_log = logs + "/latest.log";
|
||||
unlink(latest_log.c_str());
|
||||
if (symlink(file.c_str(), latest_log.c_str()) != 0) {
|
||||
WARN("Unable To Create Latest Log Symlink: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Create File
|
||||
log_fd = open(log_filename.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if (log_fd == -1) {
|
||||
ERR("Unable To Create Log File: %s", strerror(errno));
|
||||
}
|
||||
reborn_set_log(log_fd);
|
||||
}
|
||||
|
||||
// Setup
|
||||
#define PIPE_READ 0
|
||||
#define PIPE_WRITE 1
|
||||
#define BUFFER_SIZE 1024
|
||||
static void safe_write(int fd, const void *buf, size_t size) {
|
||||
const ssize_t bytes_written = write(fd, buf, size);
|
||||
if (bytes_written < 0) {
|
||||
ERR("Unable To Write Data: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
void setup_crash_report() {
|
||||
// Setup Logging
|
||||
setup_log_file();
|
||||
|
||||
// Store Output
|
||||
int output_pipe[2];
|
||||
safe_pipe2(output_pipe, 0);
|
||||
int error_pipe[2];
|
||||
safe_pipe2(error_pipe, 0);
|
||||
int input_pipe[2];
|
||||
safe_pipe2(input_pipe, 0);
|
||||
|
||||
// Fork
|
||||
pid_t ret = fork();
|
||||
if (ret == -1) {
|
||||
ERR("Unable To Fork: %s", strerror(errno));
|
||||
} else if (ret == 0) {
|
||||
// Child Process
|
||||
|
||||
// Pipe stdio
|
||||
dup2(output_pipe[PIPE_WRITE], STDOUT_FILENO);
|
||||
close(output_pipe[PIPE_READ]);
|
||||
close(output_pipe[PIPE_WRITE]);
|
||||
dup2(error_pipe[PIPE_WRITE], STDERR_FILENO);
|
||||
close(error_pipe[PIPE_READ]);
|
||||
close(error_pipe[PIPE_WRITE]);
|
||||
dup2(input_pipe[PIPE_READ], STDIN_FILENO);
|
||||
close(input_pipe[PIPE_READ]);
|
||||
close(input_pipe[PIPE_WRITE]);
|
||||
|
||||
// Create New Process Group
|
||||
setpgid(0, 0);
|
||||
|
||||
// Kill Child If Parent Exits First
|
||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||
|
||||
// Continue Execution
|
||||
} else {
|
||||
// Install Signal Handlers
|
||||
child_pid = ret;
|
||||
struct sigaction act_sigint = {};
|
||||
act_sigint.sa_flags = SA_RESTART;
|
||||
act_sigint.sa_handler = &exit_handler;
|
||||
sigaction(SIGINT, &act_sigint, nullptr);
|
||||
struct sigaction act_sigterm = {};
|
||||
act_sigterm.sa_flags = SA_RESTART;
|
||||
act_sigterm.sa_handler = &exit_handler;
|
||||
sigaction(SIGTERM, &act_sigterm, nullptr);
|
||||
|
||||
// Close Unneeded File Descriptors
|
||||
close(output_pipe[PIPE_WRITE]);
|
||||
close(error_pipe[PIPE_WRITE]);
|
||||
close(input_pipe[PIPE_READ]);
|
||||
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = "(Crash Reporter) ";
|
||||
|
||||
// Setup Polling
|
||||
const int number_fds = 3;
|
||||
pollfd poll_fds[number_fds];
|
||||
poll_fds[0].fd = output_pipe[PIPE_READ];
|
||||
poll_fds[1].fd = error_pipe[PIPE_READ];
|
||||
poll_fds[2].fd = STDIN_FILENO;
|
||||
for (pollfd &poll_fd : poll_fds) {
|
||||
poll_fd.events = POLLIN;
|
||||
}
|
||||
|
||||
// Poll Data
|
||||
int status;
|
||||
while (waitpid(ret, &status, WNOHANG) != ret) {
|
||||
const int poll_ret = poll(poll_fds, number_fds, -1);
|
||||
if (poll_ret == -1) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
} else {
|
||||
ERR("Unable To Poll Data: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Data
|
||||
for (pollfd &poll_fd : poll_fds) {
|
||||
if (poll_fd.revents != 0) {
|
||||
if (poll_fd.revents & POLLIN) {
|
||||
char buf[BUFFER_SIZE];
|
||||
if (poll_fd.fd == STDIN_FILENO) {
|
||||
// Data Available From stdin
|
||||
int bytes_available;
|
||||
if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) {
|
||||
bytes_available = 0;
|
||||
}
|
||||
// Read
|
||||
const ssize_t bytes_read = read(poll_fd.fd, buf, BUFFER_SIZE);
|
||||
if (bytes_read == -1) {
|
||||
ERR("Unable To Read Input: %s", strerror(errno));
|
||||
}
|
||||
// Write To Child
|
||||
safe_write(input_pipe[PIPE_WRITE], buf, bytes_read);
|
||||
} else {
|
||||
// Data Available From Child's stdout/stderr
|
||||
const ssize_t bytes_read = read(poll_fd.fd, buf, BUFFER_SIZE);
|
||||
if (bytes_read == -1) {
|
||||
ERR("Unable To Read Log Data: %s", strerror(errno));
|
||||
}
|
||||
// Print To Terminal
|
||||
safe_write(poll_fd.fd == output_pipe[PIPE_READ] ? STDOUT_FILENO : STDERR_FILENO, buf, bytes_read);
|
||||
// Write To log
|
||||
safe_write(reborn_get_log_fd(), buf, bytes_read);
|
||||
}
|
||||
} else {
|
||||
// File Descriptor No Longer Accessible
|
||||
poll_fd.events = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close Pipes
|
||||
close(output_pipe[PIPE_READ]);
|
||||
close(error_pipe[PIPE_READ]);
|
||||
close(input_pipe[PIPE_WRITE]);
|
||||
|
||||
// Check If Is Crash
|
||||
const bool is_crash = !is_exit_status_success(status);
|
||||
|
||||
// Log Exit Code To log If Crash
|
||||
if (is_crash) {
|
||||
// Create Exit Code Log Line
|
||||
char *exit_status = nullptr;
|
||||
get_exit_status_string(status, &exit_status);
|
||||
const std::string exit_code_line = "[CRASH]: Terminated" + std::string(exit_status) + '\n';
|
||||
free(exit_status);
|
||||
|
||||
// Print Exit Code Log Line
|
||||
safe_write(STDERR_FILENO, exit_code_line.c_str(), strlen(exit_code_line.c_str()));
|
||||
// Write Exit Code Log Line
|
||||
safe_write(reborn_get_log_fd(), exit_code_line.c_str(), strlen(exit_code_line.c_str()));
|
||||
}
|
||||
|
||||
// Close Log File
|
||||
close(log_fd);
|
||||
unsetenv(_MCPI_LOG_FD_ENV);
|
||||
|
||||
// Show Crash Log
|
||||
if (is_crash && !reborn_is_headless()) {
|
||||
show_report(log_filename.c_str());
|
||||
}
|
||||
|
||||
// Exit
|
||||
exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void setup_crash_report();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
35
launcher/src/logger/crash-report.cpp
Normal file
35
launcher/src/logger/crash-report.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
// Show Crash Report Dialog
|
||||
#define DIALOG_TITLE "Crash Report"
|
||||
#define CRASH_REPORT_DIALOG_WIDTH "640"
|
||||
#define CRASH_REPORT_DIALOG_HEIGHT "480"
|
||||
void show_report(const char *log_filename) {
|
||||
// Fork
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
// Child
|
||||
setsid();
|
||||
ALLOC_CHECK(freopen("/dev/null", "w", stdout));
|
||||
ALLOC_CHECK(freopen("/dev/null", "w", stderr));
|
||||
ALLOC_CHECK(freopen("/dev/null", "r", stdin));
|
||||
const char *command[] = {
|
||||
"zenity",
|
||||
"--title", DIALOG_TITLE,
|
||||
"--name", MCPI_APP_ID,
|
||||
"--width", CRASH_REPORT_DIALOG_WIDTH,
|
||||
"--height", CRASH_REPORT_DIALOG_HEIGHT,
|
||||
"--text-info",
|
||||
"--text", MCPI_APP_TITLE " has crashed!\n\nNeed help? Consider asking on the <a href=\"" MCPI_DISCORD_INVITE "\">Discord server</a>! <i>If you believe this is a problem with " MCPI_APP_TITLE " itself, please upload this crash report to the #bugs Discord channel.</i>",
|
||||
"--filename", log_filename,
|
||||
"--no-wrap",
|
||||
"--font", "Monospace",
|
||||
"--save-filename", MCPI_VARIANT_NAME "-crash-report.log",
|
||||
"--ok-label", "Exit",
|
||||
nullptr
|
||||
};
|
||||
safe_execvpe(command, (const char *const *) environ);
|
||||
}
|
||||
}
|
142
launcher/src/logger/logger.cpp
Normal file
142
launcher/src/logger/logger.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <csignal>
|
||||
#include <poll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
// Exit Handler
|
||||
static pid_t child_pid = -1;
|
||||
static void exit_handler(__attribute__((unused)) int signal) {
|
||||
// Murder
|
||||
kill(child_pid, SIGTERM);
|
||||
}
|
||||
|
||||
// Log File
|
||||
static std::string log_filename;
|
||||
static int log_fd;
|
||||
static void setup_log_file() {
|
||||
// Get Log Directory
|
||||
const std::string home = std::string(getenv(_MCPI_HOME_ENV)) + get_home_subdirectory_for_game_data();
|
||||
ensure_directory(home.c_str());
|
||||
const std::string logs = home + "/logs";
|
||||
ensure_directory(logs.c_str());
|
||||
|
||||
// Get Timestamp
|
||||
time_t raw_time;
|
||||
time(&raw_time);
|
||||
const tm *time_info = localtime(&raw_time);
|
||||
char time[512];
|
||||
strftime(time, 512, "%Y-%m-%d", time_info);
|
||||
|
||||
// Get Log Filename
|
||||
std::string file;
|
||||
int num = 1;
|
||||
do {
|
||||
file = std::string(time) + '-' + std::to_string(num) + ".log";
|
||||
log_filename = logs + '/' + file;
|
||||
num++;
|
||||
} while (access(log_filename.c_str(), F_OK) != -1);
|
||||
|
||||
// Create latest.log Symlink
|
||||
const std::string latest_log = logs + "/latest.log";
|
||||
unlink(latest_log.c_str());
|
||||
if (symlink(file.c_str(), latest_log.c_str()) != 0) {
|
||||
WARN("Unable To Create Latest Log Symlink: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Create File
|
||||
log_fd = open(log_filename.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if (log_fd == -1) {
|
||||
ERR("Unable To Create Log File: %s", strerror(errno));
|
||||
}
|
||||
reborn_set_log(log_fd);
|
||||
}
|
||||
|
||||
// Setup
|
||||
void setup_logger() {
|
||||
// Setup Logging
|
||||
setup_log_file();
|
||||
|
||||
// Fork
|
||||
std::optional<Process> child = fork_with_stdio();
|
||||
if (!child) {
|
||||
// Child Process
|
||||
|
||||
// Create New Process Group
|
||||
setpgid(0, 0);
|
||||
|
||||
// Continue Execution
|
||||
} else {
|
||||
// Set Debug Tag
|
||||
reborn_debug_tag = "(Logger) ";
|
||||
DEBUG("Writing To: %s", log_filename.c_str());
|
||||
|
||||
// Install Signal Handlers
|
||||
child_pid = child->pid;
|
||||
struct sigaction act_sigint = {};
|
||||
act_sigint.sa_flags = SA_RESTART;
|
||||
act_sigint.sa_handler = &exit_handler;
|
||||
sigaction(SIGINT, &act_sigint, nullptr);
|
||||
struct sigaction act_sigterm = {};
|
||||
act_sigterm.sa_flags = SA_RESTART;
|
||||
act_sigterm.sa_handler = &exit_handler;
|
||||
sigaction(SIGTERM, &act_sigterm, nullptr);
|
||||
|
||||
// Poll
|
||||
poll_fds({child->fds[0], child->fds[1], STDIN_FILENO}, [&child](const int i, const size_t size, unsigned char *buf) {
|
||||
if (i == 0 || i == 1) {
|
||||
// stdout/stderr
|
||||
|
||||
// Print To Terminal
|
||||
safe_write(i == 0 ? STDOUT_FILENO : STDERR_FILENO, buf, size);
|
||||
// Write To log
|
||||
safe_write(reborn_get_log_fd(), buf, size);
|
||||
} else {
|
||||
// stdin
|
||||
|
||||
// Write To Child
|
||||
safe_write(child->fds[2], buf, size);
|
||||
}
|
||||
});
|
||||
|
||||
// Get Exit Status
|
||||
const int status = child->close();
|
||||
const bool is_crash = !is_exit_status_success(status);
|
||||
|
||||
// Log Exit Code To log If Crash
|
||||
if (is_crash) {
|
||||
// Create Exit Code Log Line
|
||||
const std::string exit_status = get_exit_status_string(status);
|
||||
const std::string exit_code_line = "[CRASH]: Terminated" + exit_status + '\n';
|
||||
|
||||
// Print Exit Code Log Line
|
||||
safe_write(STDERR_FILENO, exit_code_line.c_str(), exit_code_line.size());
|
||||
// Write Exit Code Log Line
|
||||
safe_write(reborn_get_log_fd(), exit_code_line.c_str(), exit_code_line.size());
|
||||
}
|
||||
|
||||
// Close Log File
|
||||
close(log_fd);
|
||||
unsetenv(_MCPI_LOG_FD_ENV);
|
||||
|
||||
// Show Crash Log
|
||||
if (is_crash && !reborn_is_headless()) {
|
||||
show_report(log_filename.c_str());
|
||||
}
|
||||
|
||||
// Exit
|
||||
exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
|
||||
}
|
||||
}
|
4
launcher/src/logger/logger.h
Normal file
4
launcher/src/logger/logger.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
void setup_logger();
|
||||
void show_report(const char *log_filename);
|
@ -1,11 +1,10 @@
|
||||
#include <cstdlib>
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
#include "bootstrap/bootstrap.h"
|
||||
#include "options/parser.h"
|
||||
#include "crash-report.h"
|
||||
#include "util.h"
|
||||
#include "logger/logger.h"
|
||||
#include "util/util.h"
|
||||
#include "client/configuration.h"
|
||||
|
||||
// Bind Options To Environmental Variable
|
||||
@ -45,7 +44,8 @@ static void setup_environment(const options_t &options) {
|
||||
}
|
||||
|
||||
// Setup MCPI_HOME
|
||||
if (const char *custom_profile_directory = getenv(MCPI_PROFILE_DIRECTORY_ENV); custom_profile_directory != nullptr) {
|
||||
const char *custom_profile_directory = getenv(MCPI_PROFILE_DIRECTORY_ENV);
|
||||
if (custom_profile_directory != nullptr) {
|
||||
// Custom Directory
|
||||
custom_profile_directory = realpath(custom_profile_directory, nullptr);
|
||||
ALLOC_CHECK(custom_profile_directory);
|
||||
@ -86,8 +86,8 @@ static void start_game(const options_t &options) {
|
||||
setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
|
||||
// Setup Crash Reporting
|
||||
if (!options.disable_crash_report) {
|
||||
setup_crash_report();
|
||||
if (!options.disable_logger) {
|
||||
setup_logger();
|
||||
}
|
||||
|
||||
// Configure Client Options
|
||||
|
@ -1,6 +1,6 @@
|
||||
OPTION(debug, "debug", 'd', "Enable Debug Logging")
|
||||
OPTION(copy_sdk, "copy-sdk", -2, "Extract Modding SDK And Exit")
|
||||
OPTION(disable_crash_report, "disable-crash-report", -1, "Disable Crash Report Dialog")
|
||||
OPTION(disable_logger, "disable-logger", -1, "Disable Logger (And Crash Report Dialog)")
|
||||
OPTION(use_default, "default", -3, "Skip Client-Mode Configuration Dialogs")
|
||||
OPTION(no_cache, "no-cache", -4, "Disable Client-Mode Configuration Cache")
|
||||
OPTION(wipe_cache, "wipe-cache", -5, "Wipe Cached Client-Mode Configuration And Exit")
|
||||
|
@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define MCPI_PATCHED_DIR "/tmp/.minecraft-pi-patched"
|
||||
|
||||
void patch_mcpi_elf_dependencies(const std::string &original_path, char *new_path, const std::string &interpreter, const std::vector<std::string> &rpath, const std::vector<std::string> &mods);
|
@ -1,6 +1,6 @@
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
#include "../bootstrap/bootstrap.h"
|
||||
#include "util.h"
|
||||
|
||||
// Log
|
@ -5,10 +5,8 @@
|
||||
// Simpler Version Of run_command()
|
||||
void run_simple_command(const char *const command[], const char *error) {
|
||||
int status = 0;
|
||||
char *output = run_command(command, &status, nullptr);
|
||||
if (output != nullptr) {
|
||||
free(output);
|
||||
}
|
||||
const std::vector<unsigned char> *output = run_command(command, &status);
|
||||
delete output;
|
||||
if (!is_exit_status_success(status)) {
|
||||
ERR("%s", error);
|
||||
}
|
@ -7,3 +7,5 @@ void run_simple_command(const char *const command[], const char *error);
|
||||
void chop_last_component(std::string &str);
|
||||
std::string safe_realpath(const std::string &path);
|
||||
std::string get_binary_directory();
|
||||
|
||||
void copy_sdk(const std::string &binary_directory, bool log_with_debug);
|
@ -6,12 +6,12 @@ configure_file(include/libreborn/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/includ
|
||||
|
||||
# Util
|
||||
add_library(reborn-util SHARED
|
||||
src/util/exec.c
|
||||
src/util/string.c
|
||||
src/util/util.c
|
||||
src/util/log.c
|
||||
src/util/exec.cpp
|
||||
src/util/string.cpp
|
||||
src/util/util.cpp
|
||||
src/util/log.cpp
|
||||
src/util/cp437.cpp
|
||||
src/util/env.c
|
||||
src/util/env.cpp
|
||||
)
|
||||
target_include_directories(
|
||||
reborn-util
|
||||
|
@ -1,16 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ENV(name, ...) extern const char *const name##_ENV;
|
||||
#include "env-list.h"
|
||||
#undef ENV
|
||||
|
||||
int is_env_var_internal(const char *env);
|
||||
bool is_env_var_internal(const char *env);
|
||||
void clear_internal_env_vars();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
// Set Environmental Variable
|
||||
void set_and_print_env(const char *name, const char *value);
|
@ -1,23 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include "log.h"
|
||||
#include "string.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Set Environmental Variable
|
||||
void set_and_print_env(const char *name, const char *value);
|
||||
// fork() With I/O
|
||||
struct Process {
|
||||
static constexpr int fd_count = 3;
|
||||
Process(pid_t pid_, std::array<int, fd_count> fds_);
|
||||
[[nodiscard]] int close() const;
|
||||
const pid_t pid;
|
||||
const std::array<int, fd_count> fds;
|
||||
};
|
||||
std::optional<Process> fork_with_stdio();
|
||||
void poll_fds(const std::vector<int> &fds, const std::function<void(int, size_t, unsigned char *)> &on_data);
|
||||
|
||||
// Safe execvpe()
|
||||
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]);
|
||||
@ -26,12 +24,8 @@ __attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char
|
||||
#define CHILD_PROCESS_TAG "(Child Process) "
|
||||
|
||||
// Run Command And Get Output
|
||||
char *run_command(const char *const command[], int *exit_status, size_t *output_size);
|
||||
std::vector<unsigned char> *run_command(const char *const command[], int *exit_status);
|
||||
#define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
||||
|
||||
// Get Exit Status String
|
||||
void get_exit_status_string(int status, char **out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
std::string get_exit_status_string(int status);
|
@ -1,11 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
// Log File
|
||||
int reborn_get_log_fd();
|
||||
@ -29,7 +25,3 @@ int reborn_get_debug_fd();
|
||||
WARN(__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1,11 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// Patching Functions
|
||||
|
||||
#if defined(REBORN_HAS_PATCH_CODE) && defined(__cplusplus)
|
||||
|
||||
#include <string>
|
||||
|
||||
// Patching Functions
|
||||
#if defined(REBORN_HAS_PATCH_CODE)
|
||||
|
||||
// Init
|
||||
void reborn_init_patch();
|
||||
|
||||
|
@ -1,19 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <string>
|
||||
|
||||
// Sanitize String
|
||||
void sanitize_string(char *str, int max_length, int allow_newlines);
|
||||
void sanitize_string(std::string &str, int max_length, bool allow_newlines);
|
||||
|
||||
// CP437
|
||||
char *to_cp437(const char *input);
|
||||
char *from_cp437(const char *input);
|
||||
|
||||
// Starts With
|
||||
int starts_with(const char *str, const char *prefix);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
std::string to_cp437(const std::string &input);
|
||||
std::string from_cp437(const std::string &input);
|
@ -1,16 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <dlfcn.h>
|
||||
#include <array>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
// Check Memory Allocation
|
||||
#define ALLOC_CHECK(obj) \
|
||||
{ \
|
||||
if (obj == NULL) { \
|
||||
if ((obj) == nullptr) { \
|
||||
ERR("Memory Allocation Failed"); \
|
||||
} \
|
||||
}
|
||||
@ -41,23 +42,18 @@
|
||||
} \
|
||||
return func; \
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
#define hooked_function_setup extern "C"
|
||||
#else
|
||||
#define hooked_function_setup
|
||||
#endif
|
||||
#define HOOK(name, return_type, args) \
|
||||
EXTERNAL_FUNC(name, return_type, args) \
|
||||
hooked_function_setup __attribute__((__used__)) return_type name args
|
||||
|
||||