This commit is contained in:
parent
bdeb45eed2
commit
03312f44b6
@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
**2.3.1**
|
||||
* Internal Refactor Of ``libreborn``
|
||||
* Remove Use Of ``/bin/sh``
|
||||
|
||||
**2.3.0**
|
||||
* Switch To AppImage For Packaging
|
||||
* Prevent OpenAL From Crashing When Out Of Memory
|
||||
|
BIN
images/start.png
BIN
images/start.png
Binary file not shown.
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
@ -8,7 +8,7 @@ if(BUILD_NATIVE_COMPONENTS)
|
||||
else()
|
||||
target_sources(launcher PRIVATE src/client/launcher.cpp)
|
||||
endif()
|
||||
target_link_libraries(launcher reborn-headers)
|
||||
target_link_libraries(launcher reborn-util)
|
||||
# Install
|
||||
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
|
||||
install_symlink("../${MCPI_INSTALL_DIR}/launcher" "bin/${MCPI_VARIANT_NAME}")
|
||||
|
@ -313,7 +313,7 @@ void bootstrap(int argc, char *argv[]) {
|
||||
|
||||
// Arguments
|
||||
int argv_start = 2; // argv = &new_args[argv_start]
|
||||
char *new_args[argv_start /* 2 Potential Prefix Arguments (QEMU And Linker) */ + argc + 1 /* NULL-Terminator */]; //
|
||||
const char *new_args[argv_start /* 2 Potential Prefix Arguments (QEMU And Linker) */ + argc + 1 /* NULL-Terminator */]; //
|
||||
|
||||
// Copy Existing Arguments
|
||||
for (int i = 1; i < argc; i++) {
|
||||
@ -344,6 +344,6 @@ void bootstrap(int argc, char *argv[]) {
|
||||
#endif
|
||||
|
||||
// Run
|
||||
char **new_argv = &new_args[argv_start];
|
||||
safe_execvpe(new_argv[0], new_argv, environ);
|
||||
const char **new_argv = &new_args[argv_start];
|
||||
safe_execvpe(new_argv, (const char *const *) environ);
|
||||
}
|
||||
|
@ -37,49 +37,8 @@ static void load_available_feature_flags(std::function<void(std::string)> callba
|
||||
}
|
||||
}
|
||||
|
||||
// Run Command And Get Output
|
||||
static char *run_command(char *command[], int *return_code) {
|
||||
// Store Output
|
||||
int output_pipe[2];
|
||||
safe_pipe2(output_pipe, 0);
|
||||
// Run
|
||||
pid_t ret = fork();
|
||||
if (ret == -1) {
|
||||
ERR("Unable To Run Command: %s", strerror(errno));
|
||||
} else if (ret == 0) {
|
||||
// Child Process
|
||||
|
||||
// Pipe stdout
|
||||
dup2(output_pipe[1], STDOUT_FILENO);
|
||||
close(output_pipe[0]);
|
||||
close(output_pipe[1]);
|
||||
|
||||
// Run
|
||||
safe_execvpe(command[0], command, environ);
|
||||
} else {
|
||||
// Parent Process
|
||||
|
||||
// Read stdout
|
||||
close(output_pipe[1]);
|
||||
char *output = NULL;
|
||||
char c;
|
||||
int bytes_read = 0;
|
||||
while ((bytes_read = read(output_pipe[0], (void *) &c, 1)) > 0) {
|
||||
string_append(&output, "%c", c);
|
||||
}
|
||||
close(output_pipe[0]);
|
||||
|
||||
// Get Return Code
|
||||
int status;
|
||||
waitpid(ret, &status, 0);
|
||||
*return_code = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
|
||||
|
||||
// Return
|
||||
return output;
|
||||
}
|
||||
}
|
||||
// Run Command And Set Environmental Variable
|
||||
static void run_command_and_set_env(const char *env_name, char *command[]) {
|
||||
static void run_command_and_set_env(const char *env_name, const char *command[]) {
|
||||
// Only Run If Environmental Variable Is NULL
|
||||
if (getenv(env_name) == NULL) {
|
||||
// Run
|
||||
@ -93,6 +52,8 @@ static void run_command_and_set_env(const char *env_name, char *command[]) {
|
||||
}
|
||||
// Set
|
||||
set_and_print_env(env_name, output);
|
||||
// Free
|
||||
free(output);
|
||||
}
|
||||
// Check Return Code
|
||||
if (return_code != 0) {
|
||||
@ -107,7 +68,7 @@ static void run_zenity_and_set_env(const char *env_name, std::vector<std::string
|
||||
std::vector<std::string> full_command;
|
||||
full_command.push_back("zenity");
|
||||
full_command.push_back("--class");
|
||||
full_command.push_back("Minecraft: Pi Edition: Reborn");
|
||||
full_command.push_back(GUI_TITLE);
|
||||
full_command.insert(full_command.end(), command.begin(), command.end());
|
||||
// Convert To C Array
|
||||
const char *full_command_array[full_command.size() + 1];
|
||||
@ -116,7 +77,7 @@ static void run_zenity_and_set_env(const char *env_name, std::vector<std::string
|
||||
}
|
||||
full_command_array[full_command.size()] = NULL;
|
||||
// Run
|
||||
run_command_and_set_env(env_name, (char **) full_command_array);
|
||||
run_command_and_set_env(env_name, full_command_array);
|
||||
}
|
||||
|
||||
// Launch
|
||||
|
@ -3,52 +3,55 @@
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "ldconfig.h"
|
||||
|
||||
char *get_full_library_search_path() {
|
||||
std::string output;
|
||||
std::string processed_output;
|
||||
// Run
|
||||
FILE *file = popen("/sbin/ldconfig -NXv 2> /dev/null", "r");
|
||||
int return_code;
|
||||
const char *ldconfig_argv[] = {"/sbin/ldconfig", "-NXv", NULL};
|
||||
char *output = run_command(ldconfig_argv, &return_code);
|
||||
std::stringstream output_stream((std::string(output)));
|
||||
// Check Exit Code
|
||||
if (return_code != 0) {
|
||||
ERR("ldconfig Failed: Exit Code: %i", return_code);
|
||||
}
|
||||
|
||||
// Read
|
||||
int running = 1;
|
||||
while (running) {
|
||||
char *line = NULL;
|
||||
size_t length = 0;
|
||||
if (getline(&line, &length, file) != -1) {
|
||||
// Convert to C++ String
|
||||
std::string str(line);
|
||||
std::string line;
|
||||
if (std::getline(output_stream, line)) {
|
||||
// Remove Newline
|
||||
if (str.size() > 0 && str[str.size() - 1] == '\n') {
|
||||
str.pop_back();
|
||||
if (line.size() > 0 && line[line.size() - 1] == '\n') {
|
||||
line.pop_back();
|
||||
}
|
||||
// Interpret
|
||||
if (str.size() >= 2 && str[0] != '\t' && str[str.size() - 1] == ':') {
|
||||
if (line.size() >= 2 && line[0] != '\t' && line[line.size() - 1] == ':') {
|
||||
// Blacklist RPI Legacy GL Drivers
|
||||
#define RPI_LEGACY_GL_PATH "/opt/vc"
|
||||
if (str.rfind(RPI_LEGACY_GL_PATH ":", 0) != 0 && str.rfind(RPI_LEGACY_GL_PATH "/", 0) != 0) {
|
||||
output.append(str);
|
||||
if (line.rfind(RPI_LEGACY_GL_PATH ":", 0) != 0 && line.rfind(RPI_LEGACY_GL_PATH "/", 0) != 0) {
|
||||
processed_output.append(line);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
running = 0;
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
// Free Output
|
||||
free(output);
|
||||
|
||||
// Remove Colon
|
||||
if (output.size() > 0 && output[output.size() - 1] == ':') {
|
||||
output.pop_back();
|
||||
}
|
||||
// Close Process
|
||||
int ret = pclose(file);
|
||||
if (ret == -1) {
|
||||
ERR("ldconfig Failed: %s", strerror(errno));
|
||||
} else if (ret != 0) {
|
||||
ERR("ldconfig Failed: Exit Code: %i", ret);
|
||||
if (processed_output.size() > 0 && processed_output[processed_output.size() - 1] == ':') {
|
||||
processed_output.pop_back();
|
||||
}
|
||||
|
||||
// Return
|
||||
char *output_str = strdup(output.c_str());
|
||||
char *output_str = strdup(processed_output.c_str());
|
||||
ALLOC_CHECK(output_str);
|
||||
return output_str;
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
project(libreborn)
|
||||
|
||||
add_library(reborn-headers INTERFACE)
|
||||
target_include_directories(reborn-headers INTERFACE include)
|
||||
add_library(reborn-util STATIC src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c)
|
||||
target_include_directories(reborn-util PUBLIC include)
|
||||
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
add_library(reborn SHARED src/patch.c)
|
||||
target_link_libraries(reborn dl reborn-headers)
|
||||
target_compile_definitions(reborn PUBLIC -DREBORN_HAS_COMPILED_CODE)
|
||||
add_library(reborn-patch SHARED src/patch/patch.c)
|
||||
target_link_libraries(reborn-patch dl reborn-util)
|
||||
target_compile_definitions(reborn-patch PUBLIC -DREBORN_HAS_PATCH_CODE)
|
||||
# Install
|
||||
install(TARGETS reborn DESTINATION "${MCPI_LIB_DIR}")
|
||||
install(TARGETS reborn-patch DESTINATION "${MCPI_LIB_DIR}")
|
||||
endif()
|
||||
|
3
libreborn/include/libreborn/config.h
Normal file
3
libreborn/include/libreborn/config.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define GUI_TITLE "Minecraft: Pi Edition: Reborn"
|
@ -9,55 +9,14 @@
|
||||
#include "log.h"
|
||||
#include "exec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Find And Iterate Over All .text Sections In Current Binary
|
||||
typedef void (*text_section_callback_t)(ElfW(Addr) section, ElfW(Word) size, void *data);
|
||||
static inline void iterate_text_sections(text_section_callback_t callback, void *data) {
|
||||
// Load Main Binary
|
||||
FILE *file_obj = fopen(getenv("MCPI_EXECUTABLE_PATH"), "rb");
|
||||
void iterate_text_sections(text_section_callback_t callback, void *data);
|
||||
|
||||
// Verify Binary
|
||||
if (!file_obj) {
|
||||
ERR("%s", "Unable To Open Current Binary");
|
||||
}
|
||||
|
||||
// Get File Size
|
||||
fseek(file_obj, 0L, SEEK_END);
|
||||
long int file_size = ftell(file_obj);
|
||||
fseek(file_obj, 0L, SEEK_SET);
|
||||
|
||||
// Map File To Pointer
|
||||
unsigned char *file_map = (unsigned char *) mmap(0, file_size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0);
|
||||
|
||||
// Parse ELF
|
||||
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_map;
|
||||
ElfW(Shdr) *elf_section_headers = (ElfW(Shdr) *) (file_map + elf_header->e_shoff);
|
||||
int elf_section_header_count = elf_header->e_shnum;
|
||||
|
||||
// Locate Section Names
|
||||
ElfW(Shdr) elf_shstrtab = elf_section_headers[elf_header->e_shstrndx];
|
||||
unsigned char *elf_shstrtab_p = file_map + elf_shstrtab.sh_offset;
|
||||
|
||||
// Track .text Sections
|
||||
int text_sections = 0;
|
||||
|
||||
// Iterate Sections
|
||||
for (int i = 0; i < elf_section_header_count; ++i) {
|
||||
ElfW(Shdr) header = elf_section_headers[i];
|
||||
char *name = (char *) (elf_shstrtab_p + header.sh_name);
|
||||
// Check Section Type
|
||||
if (strcmp(name, ".text") == 0) {
|
||||
// .text Section
|
||||
(*callback)(header.sh_addr, header.sh_size, data);
|
||||
text_sections++;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure At Least .text Section Was Scanned
|
||||
if (text_sections < 1) {
|
||||
ERR("%s", "Unable To Find .text Sectons");
|
||||
}
|
||||
|
||||
// Unmap And Close File
|
||||
munmap(file_map, file_size);
|
||||
fclose(file_obj);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -4,60 +4,34 @@
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "string.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Safe execvpe()
|
||||
__attribute__((noreturn)) static inline void safe_execvpe(const char *pathname, char *argv[], char *const envp[]) {
|
||||
argv[0] = (char *) pathname;
|
||||
int ret = execvpe(pathname, argv, envp);
|
||||
if (ret == -1) {
|
||||
ERR("Unable To Execute Program: %s: %s", pathname, strerror(errno));
|
||||
} else {
|
||||
ERR("%s", "Unknown execvpe() Error");
|
||||
}
|
||||
}
|
||||
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]);
|
||||
|
||||
// Chop Off Last Component
|
||||
static inline void chop_last_component(char **str) {
|
||||
size_t length = strlen(*str);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
size_t j = length - i - 1;
|
||||
if ((*str)[j] == '/') {
|
||||
(*str)[j] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void chop_last_component(char **str);
|
||||
// Get Binary Directory (Remember To Free)
|
||||
static inline char *get_binary_directory() {
|
||||
// Get Path To Current Executable
|
||||
char *exe = realpath("/proc/self/exe", NULL);
|
||||
ALLOC_CHECK(exe);
|
||||
|
||||
// Chop Off Last Component
|
||||
chop_last_component(&exe);
|
||||
|
||||
// Return
|
||||
return exe;
|
||||
}
|
||||
char *get_binary_directory();
|
||||
|
||||
// Safe execvpe() Relative To Binary
|
||||
__attribute__((noreturn)) static inline void safe_execvpe_relative_to_binary(const char *pathname, char *argv[], char *const envp[]) {
|
||||
// Get Binary Directory
|
||||
char *binary_directory = get_binary_directory();
|
||||
// Create Full Path
|
||||
char *full_path = NULL;
|
||||
safe_asprintf(&full_path, "%s/%s", binary_directory, pathname);
|
||||
// Free Binary Directory
|
||||
free(binary_directory);
|
||||
// Run
|
||||
safe_execvpe(full_path, argv, envp);
|
||||
}
|
||||
__attribute__((noreturn)) void safe_execvpe_relative_to_binary(const char *const argv[], const char *const envp[]);
|
||||
|
||||
// Get MCPI Directory
|
||||
static inline char *get_mcpi_directory() {
|
||||
return getenv("MCPI_DIRECTORY");
|
||||
char *get_mcpi_directory();
|
||||
|
||||
// Run Command And Get Output
|
||||
char *run_command(const char *const command[], int *return_code);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "string.h"
|
||||
|
@ -6,7 +6,7 @@ extern "C" {
|
||||
|
||||
// Patching Functions
|
||||
|
||||
#ifdef REBORN_HAS_COMPILED_CODE
|
||||
#ifdef REBORN_HAS_PATCH_CODE
|
||||
|
||||
void _overwrite_call(const char *file, int line, void *start, void *target);
|
||||
#define overwrite_call(start, target) _overwrite_call(__FILE__, __LINE__, start, target);
|
||||
@ -23,7 +23,7 @@ void _patch(const char *file, int line, void *start, unsigned char patch[4]);
|
||||
void _patch_address(const char *file, int line, void *start, void *target);
|
||||
#define patch_address(start, target) _patch_address(__FILE__, __LINE__, start, target);
|
||||
|
||||
#endif // #ifdef REBORN_HAS_COMPILED_CODE
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -26,26 +26,13 @@
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Sanitize String
|
||||
#define MINIMUM_SAFE_CHARACTER 32
|
||||
#define MAXIMUM_SAFE_CHARACTER 126
|
||||
static inline void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
|
||||
// Store Message Length
|
||||
int length = strlen(*str);
|
||||
// Truncate Message
|
||||
if (max_length != -1 && length > max_length) {
|
||||
(*str)[max_length] = '\0';
|
||||
length = max_length;
|
||||
}
|
||||
// Loop Through Message
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (allow_newlines && ((*str)[i] == '\n' || (*str)[i] == '\r')) {
|
||||
continue;
|
||||
}
|
||||
unsigned char c = (unsigned char) (*str)[i];
|
||||
if (c < MINIMUM_SAFE_CHARACTER || c > MAXIMUM_SAFE_CHARACTER) {
|
||||
// Replace Illegal Character
|
||||
(*str)[i] = '?';
|
||||
}
|
||||
}
|
||||
void sanitize_string(char **str, int max_length, unsigned int allow_newlines);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -43,9 +43,13 @@
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Safe Version Of pipe()
|
||||
static inline void safe_pipe2(int pipefd[2], int flags) {
|
||||
if (pipe2(pipefd, flags) != 0) {
|
||||
ERR("Unable To Create Pipe: %s", strerror(errno));
|
||||
}
|
||||
void safe_pipe2(int pipefd[2], int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#ifndef __arm__
|
||||
#error "Patching Code Is ARM Only"
|
||||
#endif // #ifndef __arm__
|
||||
#endif
|
||||
|
||||
// BL Instruction Magic Number
|
||||
#define BL_INSTRUCTION 0xeb
|
53
libreborn/src/util/elf.c
Normal file
53
libreborn/src/util/elf.c
Normal file
@ -0,0 +1,53 @@
|
||||
#include <libreborn/elf.h>
|
||||
|
||||
// Find And Iterate Over All .text Sections In Current Binary
|
||||
void iterate_text_sections(text_section_callback_t callback, void *data) {
|
||||
// Load Main Binary
|
||||
FILE *file_obj = fopen(getenv("MCPI_EXECUTABLE_PATH"), "rb");
|
||||
|
||||
// Verify Binary
|
||||
if (!file_obj) {
|
||||
ERR("%s", "Unable To Open Current Binary");
|
||||
}
|
||||
|
||||
// Get File Size
|
||||
fseek(file_obj, 0L, SEEK_END);
|
||||
long int file_size = ftell(file_obj);
|
||||
fseek(file_obj, 0L, SEEK_SET);
|
||||
|
||||
// Map File To Pointer
|
||||
unsigned char *file_map = (unsigned char *) mmap(0, file_size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0);
|
||||
|
||||
// Parse ELF
|
||||
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_map;
|
||||
ElfW(Shdr) *elf_section_headers = (ElfW(Shdr) *) (file_map + elf_header->e_shoff);
|
||||
int elf_section_header_count = elf_header->e_shnum;
|
||||
|
||||
// Locate Section Names
|
||||
ElfW(Shdr) elf_shstrtab = elf_section_headers[elf_header->e_shstrndx];
|
||||
unsigned char *elf_shstrtab_p = file_map + elf_shstrtab.sh_offset;
|
||||
|
||||
// Track .text Sections
|
||||
int text_sections = 0;
|
||||
|
||||
// Iterate Sections
|
||||
for (int i = 0; i < elf_section_header_count; ++i) {
|
||||
ElfW(Shdr) header = elf_section_headers[i];
|
||||
char *name = (char *) (elf_shstrtab_p + header.sh_name);
|
||||
// Check Section Type
|
||||
if (strcmp(name, ".text") == 0) {
|
||||
// .text Section
|
||||
(*callback)(header.sh_addr, header.sh_size, data);
|
||||
text_sections++;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure At Least .text Section Was Scanned
|
||||
if (text_sections < 1) {
|
||||
ERR("%s", "Unable To Find .text Sectons");
|
||||
}
|
||||
|
||||
// Unmap And Close File
|
||||
munmap(file_map, file_size);
|
||||
fclose(file_obj);
|
||||
}
|
113
libreborn/src/util/exec.c
Normal file
113
libreborn/src/util/exec.c
Normal file
@ -0,0 +1,113 @@
|
||||
#include <libreborn/exec.h>
|
||||
|
||||
// Safe execvpe()
|
||||
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]) {
|
||||
int ret = execvpe(argv[0], (char *const *) argv, (char *const *) envp);
|
||||
if (ret == -1) {
|
||||
ERR("Unable To Execute Program: %s: %s", argv[0], strerror(errno));
|
||||
} else {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Chop Off Last Component
|
||||
void chop_last_component(char **str) {
|
||||
size_t length = strlen(*str);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
size_t j = length - i - 1;
|
||||
if ((*str)[j] == '/') {
|
||||
(*str)[j] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get Binary Directory (Remember To Free)
|
||||
char *get_binary_directory() {
|
||||
// Get Path To Current Executable
|
||||
char *exe = realpath("/proc/self/exe", NULL);
|
||||
ALLOC_CHECK(exe);
|
||||
|
||||
// Chop Off Last Component
|
||||
chop_last_component(&exe);
|
||||
|
||||
// Return
|
||||
return exe;
|
||||
}
|
||||
|
||||
// Safe execvpe() Relative To Binary
|
||||
__attribute__((noreturn)) void safe_execvpe_relative_to_binary(const char *const argv[], const char *const envp[]) {
|
||||
// Get Binary Directory
|
||||
char *binary_directory = get_binary_directory();
|
||||
// Create Full Path
|
||||
char *full_path = NULL;
|
||||
safe_asprintf(&full_path, "%s/%s", binary_directory, argv[0]);
|
||||
// Free Binary Directory
|
||||
free(binary_directory);
|
||||
|
||||
// Build New argv
|
||||
int argc;
|
||||
for (argc = 0; argv[argc] != NULL; argc++);
|
||||
const char *new_argv[argc + 1];
|
||||
for (int i = 1; i < argc; i++) {
|
||||
new_argv[i] = argv[i];
|
||||
}
|
||||
new_argv[0] = full_path;
|
||||
new_argv[argc] = NULL;
|
||||
// Run
|
||||
safe_execvpe(new_argv, envp);
|
||||
}
|
||||
|
||||
// Get MCPI Directory
|
||||
char *get_mcpi_directory() {
|
||||
return getenv("MCPI_DIRECTORY");
|
||||
}
|
||||
|
||||
// Run Command And Get Output
|
||||
char *run_command(const char *const command[], int *return_code) {
|
||||
// Store Output
|
||||
int output_pipe[2];
|
||||
safe_pipe2(output_pipe, 0);
|
||||
// Run
|
||||
pid_t ret = fork();
|
||||
if (ret == -1) {
|
||||
ERR("Unable To Run Command: %s", strerror(errno));
|
||||
} else if (ret == 0) {
|
||||
// Child Process
|
||||
|
||||
// Pipe stdout
|
||||
dup2(output_pipe[1], STDOUT_FILENO);
|
||||
close(output_pipe[0]);
|
||||
close(output_pipe[1]);
|
||||
|
||||
// Close stderr (But Not In Debug Mode)
|
||||
const char *is_debug = getenv("MCPI_DEBUG");
|
||||
if (is_debug == NULL || strlen(is_debug) < 1) {
|
||||
int null_fd = open("/dev/null", O_WRONLY);
|
||||
dup2(null_fd, STDERR_FILENO);
|
||||
close(null_fd);
|
||||
}
|
||||
|
||||
// Run
|
||||
safe_execvpe(command, (const char *const *) environ);
|
||||
} else {
|
||||
// Parent Process
|
||||
|
||||
// Read stdout
|
||||
close(output_pipe[1]);
|
||||
char *output = NULL;
|
||||
char c;
|
||||
int bytes_read = 0;
|
||||
while ((bytes_read = read(output_pipe[0], (void *) &c, 1)) > 0) {
|
||||
string_append(&output, "%c", c);
|
||||
}
|
||||
close(output_pipe[0]);
|
||||
|
||||
// Get Return Code
|
||||
int status;
|
||||
waitpid(ret, &status, 0);
|
||||
*return_code = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
|
||||
|
||||
// Return
|
||||
return output;
|
||||
}
|
||||
}
|
25
libreborn/src/util/string.c
Normal file
25
libreborn/src/util/string.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include <libreborn/string.h>
|
||||
|
||||
// Sanitize String
|
||||
#define MINIMUM_SAFE_CHARACTER 32
|
||||
#define MAXIMUM_SAFE_CHARACTER 126
|
||||
void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
|
||||
// Store Message Length
|
||||
int length = strlen(*str);
|
||||
// Truncate Message
|
||||
if (max_length != -1 && length > max_length) {
|
||||
(*str)[max_length] = '\0';
|
||||
length = max_length;
|
||||
}
|
||||
// Loop Through Message
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (allow_newlines && ((*str)[i] == '\n' || (*str)[i] == '\r')) {
|
||||
continue;
|
||||
}
|
||||
unsigned char c = (unsigned char) (*str)[i];
|
||||
if (c < MINIMUM_SAFE_CHARACTER || c > MAXIMUM_SAFE_CHARACTER) {
|
||||
// Replace Illegal Character
|
||||
(*str)[i] = '?';
|
||||
}
|
||||
}
|
||||
}
|
8
libreborn/src/util/util.c
Normal file
8
libreborn/src/util/util.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include <libreborn/util.h>
|
||||
|
||||
// Safe Version Of pipe()
|
||||
void safe_pipe2(int pipefd[2], int flags) {
|
||||
if (pipe2(pipefd, flags) != 0) {
|
||||
ERR("Unable To Create Pipe: %s", strerror(errno));
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ endif()
|
||||
# Configure Media Layer Core If Built
|
||||
if(TARGET media-layer-core)
|
||||
# Link
|
||||
target_link_libraries(media-layer-core media-layer-headers reborn-headers pthread dl)
|
||||
target_link_libraries(media-layer-core media-layer-headers reborn-util pthread dl)
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
# Find FreeImage
|
||||
find_library(FREEIMAGE_LIBRARY NAMES freeimage libfreeimage.so.3 REQUIRED)
|
||||
|
@ -6,7 +6,7 @@
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include <GLFW/glfw3.h>
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <media-layer/core.h>
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
#include "audio/engine.h"
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
|
||||
// Allow Disabling Interaction
|
||||
static void update_cursor();
|
||||
@ -222,7 +222,7 @@ static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute_
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
|
||||
// Track Media Layer State
|
||||
static int is_running = 0;
|
||||
@ -235,7 +235,7 @@ void media_set_raw_mouse_motion_enabled(int enabled) {
|
||||
if (is_running) {
|
||||
glfwSetInputMode(glfw_window, GLFW_RAW_MOUSE_MOTION, GLFW_FALSE);
|
||||
}
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
if (!raw_mouse_motion_enabled) {
|
||||
WARN("%s", "Raw mouse motion has been DISABLED, this IS NOT recommended, and should only ever be used on systems that don't support or have broken raw mouse motion.");
|
||||
}
|
||||
@ -249,7 +249,7 @@ void media_disable_vsync() {
|
||||
if (is_running) {
|
||||
glfwSwapInterval(0);
|
||||
}
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
}
|
||||
|
||||
// Init Media Layer
|
||||
@ -289,9 +289,9 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
|
||||
|
||||
// Init OpenAL
|
||||
_media_audio_init();
|
||||
#else // #ifndef MCPI_HEADLESS_MODE
|
||||
#else
|
||||
(void) title; // Mark As Used
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
|
||||
// Set State
|
||||
is_running = 1;
|
||||
@ -307,7 +307,7 @@ void media_swap_buffers() {
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
// Don't Swap Buffers In A Context-Less Window
|
||||
glfwSwapBuffers(glfw_window);
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
}
|
||||
|
||||
// Fullscreen Not Needed In Headless Mode
|
||||
@ -340,10 +340,10 @@ void media_toggle_fullscreen() {
|
||||
}
|
||||
is_fullscreen = !is_fullscreen;
|
||||
}
|
||||
#else // #ifndef MCPI_HEADLESS_MODE
|
||||
#else
|
||||
void media_toggle_fullscreen() {
|
||||
}
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
|
||||
// Intercept SDL Events
|
||||
void _media_handle_SDL_PollEvent() {
|
||||
@ -359,7 +359,7 @@ void _media_handle_SDL_PollEvent() {
|
||||
SDL_PushEvent(&event);
|
||||
glfwSetWindowShouldClose(glfw_window, GLFW_FALSE);
|
||||
}
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
}
|
||||
|
||||
// Cleanup Media Layer
|
||||
@ -376,7 +376,7 @@ void media_cleanup() {
|
||||
|
||||
// Cleanup OpenAL
|
||||
_media_audio_cleanup();
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
|
||||
// Update State
|
||||
is_running = 0;
|
||||
@ -437,7 +437,7 @@ static void update_cursor() {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
}
|
||||
|
||||
// Fix SDL Cursor Visibility/Grabbing
|
||||
@ -483,7 +483,7 @@ void media_get_framebuffer_size(int *width, int *height) {
|
||||
glfwGetFramebufferSize(glfw_window, width, height);
|
||||
return;
|
||||
}
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
*width = DEFAULT_WIDTH;
|
||||
*height = DEFAULT_HEIGHT;
|
||||
}
|
||||
|
@ -122,8 +122,8 @@ __attribute__((constructor)) static void init() {
|
||||
FreeImage_Initialise(0);
|
||||
}
|
||||
|
||||
#else // #ifndef MCPI_HEADLESS_MODE
|
||||
#else
|
||||
void media_take_screenshot() {
|
||||
// NOP
|
||||
}
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
#endif
|
||||
|
@ -9,7 +9,7 @@ if(BUILD_NATIVE_COMPONENTS)
|
||||
|
||||
# Build Media Layer Proxy Client
|
||||
add_executable(media-layer-proxy-client src/client/client.cpp ${MEDIA_LAYER_PROXY_SRC})
|
||||
target_link_libraries(media-layer-proxy-client media-layer-headers reborn-headers ${MEDIA_LAYER_PROXY_LIBS})
|
||||
target_link_libraries(media-layer-proxy-client media-layer-headers reborn-util ${MEDIA_LAYER_PROXY_LIBS})
|
||||
target_compile_definitions(media-layer-proxy-client PRIVATE -DMEDIA_LAYER_PROXY_CLIENT)
|
||||
# Install
|
||||
install(TARGETS media-layer-proxy-client DESTINATION "${MCPI_BIN_DIR}")
|
||||
@ -20,7 +20,7 @@ if(BUILD_ARM_COMPONENTS)
|
||||
|
||||
# Build Media Layer Proxy Server
|
||||
add_library(media-layer-core SHARED src/server/server.cpp ${MEDIA_LAYER_PROXY_SRC})
|
||||
target_link_libraries(media-layer-core media-layer-headers reborn-headers)
|
||||
target_link_libraries(media-layer-core media-layer-headers reborn-util)
|
||||
target_compile_definitions(media-layer-core PRIVATE -DMEDIA_LAYER_PROXY_SERVER)
|
||||
# Symlink GLESv1_CM To Media Layer Proxy Server
|
||||
install_symlink("libmedia-layer-core.so" "${MCPI_LIB_DIR}/libGLESv1_CM.so.1")
|
||||
|
@ -77,10 +77,10 @@ static void start_media_layer_proxy_client(int read, int write) {
|
||||
safe_asprintf(&read_str, "%i", read);
|
||||
char *write_str = NULL;
|
||||
safe_asprintf(&write_str, "%i", write);
|
||||
char *argv[] = {NULL /* Updated By safe_execvpe() */, read_str, write_str, NULL};
|
||||
const char *argv[] = {"media-layer-proxy-client", read_str, write_str, NULL};
|
||||
|
||||
// Run
|
||||
safe_execvpe("media-layer-proxy-client", argv, environ);
|
||||
safe_execvpe(argv, (const char *const *) environ);
|
||||
} else {
|
||||
// Parent Process
|
||||
_client_pid = ret;
|
||||
|
@ -14,11 +14,11 @@ if(BUILD_ARM_COMPONENTS)
|
||||
|
||||
# Stub EGL
|
||||
add_library(EGL SHARED src/EGL.c)
|
||||
target_link_libraries(EGL reborn-headers media-layer-headers)
|
||||
target_link_libraries(EGL reborn-util media-layer-headers)
|
||||
set_target_properties(EGL PROPERTIES SOVERSION "1")
|
||||
# Stub X11
|
||||
add_library(X11 SHARED src/X11.c)
|
||||
target_link_libraries(X11 reborn-headers media-layer-headers)
|
||||
target_link_libraries(X11 reborn-util media-layer-headers)
|
||||
set_target_properties(X11 PROPERTIES SOVERSION "6")
|
||||
# Install
|
||||
if(MCPI_HEADLESS_MODE OR MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
|
@ -8,80 +8,80 @@ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
|
||||
## Mods
|
||||
|
||||
add_library(compat SHARED src/compat/compat.c src/compat/egl.c src/compat/x11.c)
|
||||
target_link_libraries(compat reborn media-layer-core)
|
||||
target_link_libraries(compat reborn-patch media-layer-core)
|
||||
|
||||
add_library(readdir SHARED src/readdir/readdir.c)
|
||||
|
||||
add_library(feature SHARED src/feature/feature.c)
|
||||
target_link_libraries(feature reborn)
|
||||
target_link_libraries(feature reborn-patch)
|
||||
|
||||
add_library(version SHARED src/version/version.cpp)
|
||||
target_link_libraries(version reborn symbols)
|
||||
target_link_libraries(version reborn-patch symbols)
|
||||
|
||||
add_library(chat SHARED src/chat/chat.cpp src/chat/ui.c)
|
||||
target_link_libraries(chat reborn symbols feature pthread)
|
||||
target_link_libraries(chat reborn-patch symbols feature pthread)
|
||||
|
||||
if(MCPI_SERVER_MODE)
|
||||
add_library(server SHARED src/server/server.cpp src/server/server_properties.cpp)
|
||||
target_link_libraries(server reborn symbols feature home misc compat dl media-layer-core pthread)
|
||||
target_link_libraries(server reborn-patch symbols feature home misc compat dl media-layer-core pthread)
|
||||
else()
|
||||
target_link_libraries(compat input sign chat home dl)
|
||||
|
||||
target_link_libraries(chat input)
|
||||
|
||||
add_library(multiplayer SHARED src/multiplayer/multiplayer.cpp)
|
||||
target_link_libraries(multiplayer reborn symbols home feature)
|
||||
target_link_libraries(multiplayer reborn-patch symbols home feature)
|
||||
|
||||
add_library(sound SHARED src/sound/sound.cpp src/sound/repository.cpp)
|
||||
target_link_libraries(sound reborn symbols feature override media-layer-core)
|
||||
target_link_libraries(sound reborn-patch symbols feature override media-layer-core)
|
||||
|
||||
add_library(camera SHARED src/camera/camera.cpp)
|
||||
target_link_libraries(camera reborn symbols media-layer-core feature home)
|
||||
target_link_libraries(camera reborn-patch symbols media-layer-core feature home)
|
||||
|
||||
add_library(input SHARED src/input/input.cpp src/input/bow.c src/input/attack.c src/input/toggle.c src/input/misc.c src/input/drop.cpp)
|
||||
target_link_libraries(input reborn symbols creative feature media-layer-core)
|
||||
target_link_libraries(input reborn-patch symbols creative feature media-layer-core)
|
||||
|
||||
add_library(sign SHARED src/sign/sign.cpp)
|
||||
target_link_libraries(sign reborn symbols feature input)
|
||||
target_link_libraries(sign reborn-patch symbols feature input)
|
||||
|
||||
add_library(creative SHARED src/creative/creative.cpp)
|
||||
target_link_libraries(creative reborn symbols feature)
|
||||
target_link_libraries(creative reborn-patch symbols feature)
|
||||
|
||||
add_library(touch SHARED src/touch/touch.c)
|
||||
target_link_libraries(touch reborn symbols feature)
|
||||
target_link_libraries(touch reborn-patch symbols feature)
|
||||
|
||||
add_library(override SHARED src/override/override.c)
|
||||
target_link_libraries(override reborn symbols dl home)
|
||||
target_link_libraries(override reborn-patch symbols dl home)
|
||||
|
||||
add_library(textures SHARED src/textures/textures.cpp)
|
||||
target_link_libraries(textures reborn symbols media-layer-core feature)
|
||||
target_link_libraries(textures reborn-patch symbols media-layer-core feature)
|
||||
|
||||
add_library(atlas SHARED src/atlas/atlas.cpp)
|
||||
target_link_libraries(atlas reborn symbols feature GLESv1_CM)
|
||||
target_link_libraries(atlas reborn-patch symbols feature GLESv1_CM)
|
||||
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
add_library(benchmark SHARED src/benchmark/benchmark.cpp)
|
||||
target_link_libraries(benchmark reborn symbols compat misc media-layer-core)
|
||||
target_link_libraries(benchmark reborn-patch symbols compat misc media-layer-core)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(game-mode SHARED src/game-mode/game-mode.c src/game-mode/game-mode.cpp)
|
||||
target_link_libraries(game-mode reborn symbols feature)
|
||||
target_link_libraries(game-mode reborn-patch symbols feature)
|
||||
|
||||
add_library(death SHARED src/death/death.cpp)
|
||||
target_link_libraries(death reborn symbols feature)
|
||||
target_link_libraries(death reborn-patch symbols feature)
|
||||
|
||||
add_library(misc SHARED src/misc/misc.c src/misc/misc.cpp src/misc/logging.cpp)
|
||||
target_link_libraries(misc reborn symbols feature GLESv1_CM)
|
||||
target_link_libraries(misc reborn-patch symbols feature GLESv1_CM)
|
||||
|
||||
add_library(options SHARED src/options/options.c)
|
||||
target_link_libraries(options reborn symbols feature)
|
||||
target_link_libraries(options reborn-patch symbols feature)
|
||||
|
||||
add_library(home SHARED src/home/home.c)
|
||||
target_link_libraries(home reborn symbols)
|
||||
target_link_libraries(home reborn-patch symbols)
|
||||
|
||||
add_library(test SHARED src/test/test.c)
|
||||
target_link_libraries(test reborn home)
|
||||
target_link_libraries(test reborn-patch home)
|
||||
|
||||
add_library(init SHARED src/init/init.c)
|
||||
target_link_libraries(init compat game-mode misc death options chat home version test media-layer-core)
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "../feature/feature.h"
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#include "../input/input.h"
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif
|
||||
#include "chat.h"
|
||||
|
||||
// Store If Chat is Enabled
|
||||
@ -39,7 +39,7 @@ static void send_api_chat_command(unsigned char *minecraft, char *str) {
|
||||
send_api_command(minecraft, command);
|
||||
free(command);
|
||||
}
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif
|
||||
|
||||
// Send Message To Players
|
||||
static void send_message(unsigned char *server_side_network_handler, char *username, char *message) {
|
||||
@ -115,7 +115,7 @@ static void send_queued_messages(unsigned char *minecraft) {
|
||||
// Unlock
|
||||
pthread_mutex_unlock(&queue_mutex);
|
||||
}
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif
|
||||
|
||||
// Init
|
||||
void init_chat() {
|
||||
@ -131,6 +131,6 @@ void init_chat() {
|
||||
// Send Messages On Input Tick
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
input_run_on_tick(send_queued_messages);
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -10,27 +10,13 @@
|
||||
#include "../input/input.h"
|
||||
|
||||
// Run Command
|
||||
static char *run_command(char *command, int *return_code) {
|
||||
static char *run_command_proper(const char *command[], int *return_code) {
|
||||
// Prepare Environment
|
||||
RESET_ENVIRONMENTAL_VARIABLE("LD_LIBRARY_PATH");
|
||||
RESET_ENVIRONMENTAL_VARIABLE("LD_PRELOAD");
|
||||
|
||||
// Start
|
||||
FILE *out = popen(command, "r");
|
||||
if (!out) {
|
||||
ERR("%s", "Failed To Run Command");
|
||||
}
|
||||
|
||||
// Record
|
||||
char *output = NULL;
|
||||
int c;
|
||||
while ((c = fgetc(out)) != EOF) {
|
||||
string_append(&output, "%c", (char) c);
|
||||
}
|
||||
|
||||
// Return
|
||||
*return_code = WEXITSTATUS(pclose(out));
|
||||
return output;
|
||||
// Run
|
||||
return run_command(command, return_code);
|
||||
}
|
||||
|
||||
// Count Chat Windows
|
||||
@ -44,7 +30,8 @@ unsigned int chat_get_counter() {
|
||||
static void *chat_thread(__attribute__((unused)) void *nop) {
|
||||
// Open
|
||||
int return_code;
|
||||
char *output = run_command("zenity --title 'Chat' --class 'Minecraft: Pi Edition: Reborn' --entry --text 'Enter Chat Message:'", &return_code);
|
||||
const char *command[] = {"zenity", "--title", "Chat", "--class", GUI_TITLE, "--entry", "--text", "Enter Chat Message:", NULL};
|
||||
char *output = run_command_proper(command, &return_code);
|
||||
// Handle Message
|
||||
if (output != NULL) {
|
||||
// Check Return Code
|
||||
@ -87,4 +74,4 @@ void chat_open() {
|
||||
pthread_create(&thread, NULL, chat_thread, NULL);
|
||||
}
|
||||
}
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif
|
||||
|
@ -18,7 +18,7 @@
|
||||
// Custom Title
|
||||
HOOK(SDL_WM_SetCaption, void, (__attribute__((unused)) const char *title, const char *icon)) {
|
||||
ensure_SDL_WM_SetCaption();
|
||||
(*real_SDL_WM_SetCaption)("Minecraft: Pi Edition: Reborn", icon);
|
||||
(*real_SDL_WM_SetCaption)(GUI_TITLE, icon);
|
||||
}
|
||||
|
||||
// Mouse Cursor Is Always Invisible In Vanilla MCPI
|
||||
@ -106,7 +106,7 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif
|
||||
|
||||
// Exit Handler
|
||||
static void exit_handler(__attribute__((unused)) int data) {
|
||||
|
@ -30,7 +30,7 @@ static int get_render_distance() {
|
||||
ERR("Invalid Render Distance: %s", distance_str);
|
||||
}
|
||||
}
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif
|
||||
|
||||
// Get Custom Username
|
||||
static char *get_username() {
|
||||
@ -86,9 +86,9 @@ void init_options() {
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
render_distance = get_render_distance();
|
||||
INFO("Setting Render Distance: %i", render_distance);
|
||||
#else // #ifndef MCPI_SERVER_MODE
|
||||
#else
|
||||
render_distance = 3;
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif
|
||||
// Server Visible
|
||||
server_visible = !feature_has("Disable Hosting LAN Worlds", 0);
|
||||
|
||||
@ -99,7 +99,7 @@ void init_options() {
|
||||
const char *username = get_username();
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
INFO("Setting Username: %s", username);
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif
|
||||
if (strcmp(*default_username, "StevePi") != 0) {
|
||||
ERR("%s", "Default Username Is Invalid");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user