mirror of
https://github.com/lindbergh-loader/lindbergh-loader.git
synced 2026-09-22 22:48:03 +03:00
Merge pull request #84 from dkeruza-neo/master
Stand alone lindbergh loader
This commit is contained in:
+4
-1
@@ -2,7 +2,10 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## ## [2.0.8]
|
||||
## [2.0.9]
|
||||
- - lindbergh elf mostly redone to make the loader work as a stand alone mode.
|
||||
|
||||
## [2.0.8]
|
||||
### Added
|
||||
- Changed preprocessor for avoiding multiple inclusions to #pragma once and clean some includes.
|
||||
### Fixed
|
||||
|
||||
+390
-260
@@ -1,4 +1,6 @@
|
||||
#include <dirent.h>
|
||||
#include <libgen.h>
|
||||
#include <linux/limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -15,13 +17,37 @@
|
||||
#define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
|
||||
#define LD_PRELOAD "LD_PRELOAD"
|
||||
#define PRELOAD_FILE_NAME "lindbergh.so"
|
||||
#define PRELOAD_FILE_FLATPAK "/app/lib32/lindbergh.so"
|
||||
#define TEAM "bobbydilley, retrofan, dkeruza-neo, doozer, francesco, rolel, caviar-x"
|
||||
#define LINDBERGH_CONFIG_PATH "LINDBERGH_CONFIG_PATH"
|
||||
#define MAX_PATH_LEN 1024
|
||||
|
||||
/**
|
||||
* @brief Calculates the CRC32 of a single byte.
|
||||
*
|
||||
* This function calculates the CRC32 value for a given byte of data.
|
||||
*
|
||||
* @param crc The current CRC32 value.
|
||||
* @param data The byte of data to calculate the CRC32 for.
|
||||
* @return The updated CRC32 value.
|
||||
*/
|
||||
uint32_t calcCrc32(uint32_t crc, uint8_t data)
|
||||
{
|
||||
crc ^= data; // No shift needed; working in LSB-first order
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (crc & 1)
|
||||
{
|
||||
crc = (crc >> 1) ^ 0xEDB88320;
|
||||
}
|
||||
else
|
||||
{
|
||||
crc = (crc >> 1);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t elf_crc = 0;
|
||||
char *ldPreloadLibrary = "";
|
||||
|
||||
// List of all lindbergh executables known, not including the test executables
|
||||
char *games[] = {"main.exe",
|
||||
@@ -126,23 +152,14 @@ uint32_t cleanElfCRC32[] = {
|
||||
|
||||
int cleanElfCRC32Count = sizeof(cleanElfCRC32) / sizeof(uint32_t);
|
||||
|
||||
uint32_t calcCrc32(uint32_t crc, uint8_t data)
|
||||
{
|
||||
crc ^= data; // No shift needed; working in LSB-first order
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (crc & 1)
|
||||
{
|
||||
crc = (crc >> 1) ^ 0xEDB88320;
|
||||
}
|
||||
else
|
||||
{
|
||||
crc = (crc >> 1);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Looks up a CRC value in the cleanElfCRC32 table.
|
||||
*
|
||||
* This function searches for a given CRC value within the cleanElfCRC32 array.
|
||||
*
|
||||
* @param crc The CRC value to look up.
|
||||
* @return 1 if the CRC is found in the table, 0 otherwise.
|
||||
*/
|
||||
int lookupCrcTable(uint32_t crc)
|
||||
{
|
||||
for (int x = 0; x < cleanElfCRC32Count; x++)
|
||||
@@ -153,6 +170,73 @@ int lookupCrcTable(uint32_t crc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes double quotes from a string.
|
||||
*
|
||||
* This function iterates through the input string and removes any double quote characters.
|
||||
* It modifies the string in place.
|
||||
*
|
||||
* @param str The string to remove double quotes from.
|
||||
*/
|
||||
void removeDoubleQuotes(char *str)
|
||||
{
|
||||
if (str == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; str[i] != '\0'; i++)
|
||||
{
|
||||
if (str[i] != '"')
|
||||
{
|
||||
str[j] = str[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
str[j] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates the CRC32 of a file.
|
||||
*
|
||||
* This function calculates the CRC32 of the specified file.
|
||||
*
|
||||
* @param filename The path to the file.
|
||||
* @param crc The pointer to the variable that will contain the CRC32.
|
||||
* @return 0 if the CRC32 was calculated successfully, -1 otherwise.
|
||||
*/
|
||||
int calculateFileCRC32(const char *filename, uint32_t *crc)
|
||||
{
|
||||
FILE *file = fopen(filename, "rb");
|
||||
if (!file)
|
||||
{
|
||||
log_error("Could not open file to calculate the CRC32.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*crc = 0xFFFFFFFF;
|
||||
uint8_t buffer[4096];
|
||||
size_t bytesRead;
|
||||
|
||||
while ((bytesRead = fread(buffer, 1, sizeof(buffer), file)) > 0)
|
||||
{
|
||||
for (size_t i = 0; i < bytesRead; i++)
|
||||
{
|
||||
*crc = calcCrc32(*crc, buffer[i]);
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the ELF file is clean based on its CRC32.
|
||||
*
|
||||
* This function calculates the CRC32 of the specified ELF file and compares it
|
||||
* against a list of known clean ELF CRC32 values.
|
||||
* @param command The command line string containing the path to the ELF file.
|
||||
*/
|
||||
void isCleanElf(char *command)
|
||||
{
|
||||
char *last_space = strrchr(command, ' ');
|
||||
@@ -166,38 +250,12 @@ void isCleanElf(char *command)
|
||||
strncpy(elfName, command, length);
|
||||
elfName[length] = '\0';
|
||||
|
||||
// Remove double quotes from path if it was added.
|
||||
int j = 0;
|
||||
for (int i = 0; elfName[i] != '\0'; i++)
|
||||
{
|
||||
if (elfName[i] != '"')
|
||||
{
|
||||
elfName[j] = elfName[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
elfName[j] = '\0';
|
||||
removeDoubleQuotes(elfName);
|
||||
|
||||
FILE *file = fopen(elfName, "rb");
|
||||
if (!file)
|
||||
{
|
||||
log_error("Could not calculate the Elf CRC32.");
|
||||
uint32_t crc;
|
||||
if (calculateFileCRC32(elfName, &crc) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t crc = 0xFFFFFFFF;
|
||||
uint8_t buffer[4096];
|
||||
size_t bytesRead;
|
||||
|
||||
while ((bytesRead = fread(buffer, 1, sizeof(buffer), file)) > 0)
|
||||
{
|
||||
for (size_t i = 0; i < bytesRead; i++)
|
||||
{
|
||||
crc = calcCrc32(crc, buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
crc = crc ^ 0xFFFFFFFF;
|
||||
|
||||
if (!lookupCrcTable(crc))
|
||||
@@ -218,26 +276,27 @@ void isCleanElf(char *command)
|
||||
*/
|
||||
void testModePath(char *name)
|
||||
{
|
||||
printf("name: %s\n", name);
|
||||
char *pos;
|
||||
// Check if a different testmode elf is used
|
||||
pos = strstr(name, "/hod4M.elf");
|
||||
pos = strstr(name, "hod4M.elf");
|
||||
if (pos != NULL)
|
||||
{
|
||||
strcpy(pos, "/hod4testM.elf");
|
||||
strcpy(pos, "hod4testM.elf");
|
||||
return;
|
||||
}
|
||||
|
||||
pos = strstr(name, "/hodexRI.elf");
|
||||
pos = strstr(name, "hodexRI.elf");
|
||||
if (pos != NULL)
|
||||
{
|
||||
strcpy(pos, "/hodextestR.elf");
|
||||
strcpy(pos, "hodextestR.elf");
|
||||
return;
|
||||
}
|
||||
|
||||
pos = strstr(name, "/Jennifer\"/Jennifer");
|
||||
pos = strstr(name, "/Jennifer/\"Jennifer");
|
||||
if (pos != NULL)
|
||||
{
|
||||
strcpy(pos, "/Jennifer\"/../JenTest/JenTest");
|
||||
strcpy(pos, "/Jennifer/\"../JenTest/JenTest");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -248,17 +307,17 @@ void testModePath(char *name)
|
||||
return;
|
||||
}
|
||||
|
||||
pos = strstr(name, "/apacheM.elf");
|
||||
pos = strstr(name, "apacheM.elf");
|
||||
if (pos != NULL)
|
||||
{
|
||||
strcpy(pos, "/apachetestM.elf");
|
||||
strcpy(pos, "apachetestM.elf");
|
||||
return;
|
||||
}
|
||||
|
||||
pos = strstr(name, "/vt3_Lindbergh\"/vt3_Lindbergh");
|
||||
pos = strstr(name, "/vt3_Lindbergh/\"vt3_Lindbergh");
|
||||
if (pos != NULL)
|
||||
{
|
||||
strcpy(pos, "/vt3_Lindbergh\"/vt3_testmode");
|
||||
strcpy(pos, "/vt3_Lindbergh/\"vt3_testmode");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -273,6 +332,13 @@ void testModePath(char *name)
|
||||
strcat(name, " -t");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a given path is a valid directory.
|
||||
*
|
||||
* This function uses the stat system call to determine if the provided path
|
||||
* corresponds to a directory.
|
||||
* @param path The path to check.
|
||||
*/
|
||||
bool isValidDirectory(const char *path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
@@ -283,93 +349,122 @@ bool isValidDirectory(const char *path)
|
||||
return S_ISDIR(statbuf.st_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds a suitable 32-bit library folder.
|
||||
*
|
||||
* This function searches for a directory that is likely to contain 32-bit
|
||||
* libraries, based on a predefined list of candidate paths.
|
||||
* @return A dynamically allocated string containing the path to the found
|
||||
* directory, or NULL if no suitable directory is found.
|
||||
*/
|
||||
char *find32bLibFolder(void)
|
||||
{
|
||||
const char *candidates[] = {"lib32", "lib/i386-linux-gnu", "lib/i686-linux-gnu", "lib"};
|
||||
int num_candidates = sizeof(candidates) / sizeof(candidates[0]);
|
||||
const char *folderCandidates[] = {"/app/lib32", "/usr/lib/i386-linux-gnu", "/usr/lib/i686-linux-gnu", "/usr/lib32", "/usr/lib"};
|
||||
int numCandidates = sizeof(folderCandidates) / sizeof(folderCandidates[0]);
|
||||
|
||||
char current_path[PATH_MAX];
|
||||
char currentPath[PATH_MAX];
|
||||
struct stat st;
|
||||
char *result_path = NULL;
|
||||
char *resultPath = NULL;
|
||||
|
||||
for (int i = 0; i < num_candidates; ++i)
|
||||
for (int i = 0; i < numCandidates; ++i)
|
||||
{
|
||||
int written = snprintf(current_path, sizeof(current_path), "/usr/%s", candidates[i]);
|
||||
int written = snprintf(currentPath, sizeof(currentPath), "%s", folderCandidates[i]);
|
||||
|
||||
if (written < 0 || (size_t)written >= sizeof(current_path))
|
||||
if (written < 0 || (size_t)written >= sizeof(currentPath))
|
||||
continue;
|
||||
|
||||
if (stat(current_path, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
if (stat(currentPath, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
{
|
||||
size_t path_len = strlen(current_path);
|
||||
result_path = (char *)malloc(path_len + 1);
|
||||
size_t pathLen = strlen(currentPath);
|
||||
resultPath = (char *)malloc(pathLen + 1);
|
||||
|
||||
if (result_path == NULL)
|
||||
if (resultPath == NULL)
|
||||
{
|
||||
log_fatal("Failed to allocate memory for result path.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(result_path, current_path);
|
||||
return result_path;
|
||||
strcpy(resultPath, currentPath);
|
||||
return resultPath;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds the path to the LD_PRELOAD library.
|
||||
*
|
||||
* This function searches for the lindbergh.so library in various locations,
|
||||
* including the current directory and system library folders.
|
||||
* @return A dynamically allocated string containing the path to the library, or an empty string if not found.
|
||||
*/
|
||||
char *findLDPreloadLibrary()
|
||||
{
|
||||
const char *library_name = PRELOAD_FILE_NAME;
|
||||
static char *empty_string = "";
|
||||
char *found_path_ptr = NULL;
|
||||
char *foundPathPtr = NULL;
|
||||
|
||||
char *search_dir = find32bLibFolder();
|
||||
char *systemLibFolder = find32bLibFolder();
|
||||
|
||||
if (search_dir == NULL || search_dir[0] == '\0')
|
||||
if (systemLibFolder == NULL || systemLibFolder[0] == '\0')
|
||||
{
|
||||
log_error("Error: search_dir is NULL or empty.\n");
|
||||
return empty_string;
|
||||
log_error("Error: library folder not found.\n");
|
||||
return "";
|
||||
}
|
||||
|
||||
char full_library_path[PATH_MAX];
|
||||
char fullLibPath[PATH_MAX];
|
||||
|
||||
int len_written = snprintf(full_library_path, sizeof(full_library_path), "%s/%s", search_dir, library_name);
|
||||
int lenWritten = snprintf(fullLibPath, sizeof(fullLibPath), "%s/%s", systemLibFolder, PRELOAD_FILE_NAME);
|
||||
|
||||
if (len_written < 0 || (size_t)len_written >= sizeof(full_library_path))
|
||||
if (lenWritten < 0 || (size_t)lenWritten >= sizeof(fullLibPath))
|
||||
{
|
||||
log_error("find_preload_library_in_specific_dir: Warning: Constructed path is too long or invalid: %s/%s\n", search_dir,
|
||||
library_name);
|
||||
return empty_string;
|
||||
log_error("Warning: Constructed path is too long or invalid: %s/%s\n", systemLibFolder, PRELOAD_FILE_NAME);
|
||||
return "";
|
||||
}
|
||||
|
||||
if (access(full_library_path, F_OK) == 0)
|
||||
if (access(PRELOAD_FILE_NAME, F_OK) == 0) // lindbergh.so in current folder
|
||||
{
|
||||
found_path_ptr = (char *)malloc(strlen(full_library_path) + 1);
|
||||
if (found_path_ptr == NULL)
|
||||
{
|
||||
log_error("find_preload_library_in_specific_dir: Failed to allocate memory for result path");
|
||||
return empty_string;
|
||||
}
|
||||
char curDir[MAX_PATH_LEN];
|
||||
if (getcwd(curDir, sizeof(curDir)) == NULL)
|
||||
return "";
|
||||
size_t len = strlen(curDir) + strlen(PRELOAD_FILE_NAME) + 1;
|
||||
foundPathPtr = (char *)malloc(len + 1);
|
||||
if (foundPathPtr == NULL)
|
||||
return "";
|
||||
else
|
||||
{
|
||||
strcpy(found_path_ptr, full_library_path);
|
||||
return found_path_ptr;
|
||||
}
|
||||
snprintf(foundPathPtr, len + 1, "%s/%s", curDir, PRELOAD_FILE_NAME);
|
||||
}
|
||||
else
|
||||
else if (access(fullLibPath, F_OK) == 0) // lindbergh.so in system lib folder
|
||||
{
|
||||
return empty_string;
|
||||
foundPathPtr = (char *)malloc(strlen(fullLibPath) + 1);
|
||||
if (foundPathPtr == NULL)
|
||||
return "";
|
||||
else
|
||||
strcpy(foundPathPtr, fullLibPath);
|
||||
}
|
||||
else // lindbergh.so in the ELF folder.
|
||||
{
|
||||
return PRELOAD_FILE_NAME;
|
||||
}
|
||||
return foundPathPtr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure the environment variables are set correctly
|
||||
*
|
||||
* This function sets the LD_LIBRARY_PATH and LD_PRELOAD environment variables
|
||||
* to ensure that the game can find the necessary libraries and preload the
|
||||
* lindbergh.so library.
|
||||
*
|
||||
* @param ldLibPath The path to the LD_PRELOAD library.
|
||||
* @param curDir The current working directory.
|
||||
* @param gameDir The directory where the game is located.
|
||||
* @param zink Flag indicating whether to use Zink.
|
||||
* @param nvidia Flag indicating whether to use NVIDIA GPU.
|
||||
* to run the game.
|
||||
*/
|
||||
void setEnvironmentVariables(int isFlatpak, int zink, int nvidia)
|
||||
void setEnvironmentVariables(char *ldLibPath, char *curDir, char *gameDir, int zink, int nvidia)
|
||||
{
|
||||
// Ensure the library path is set correctly
|
||||
char libraryPath[128] = {0};
|
||||
char libraryPath[MAX_PATH_LEN] = {0};
|
||||
|
||||
const char *currentLibraryPath = getenv(LD_LIBRARY_PATH);
|
||||
if (currentLibraryPath != NULL)
|
||||
@@ -380,15 +475,33 @@ void setEnvironmentVariables(int isFlatpak, int zink, int nvidia)
|
||||
|
||||
strcat(libraryPath, ".:lib:../lib");
|
||||
|
||||
char *tmpLibPath = dirname(strdup(ldLibPath));
|
||||
|
||||
if (strcmp(tmpLibPath, ".") != 0)
|
||||
{
|
||||
strcat(libraryPath, ":");
|
||||
strcat(libraryPath, tmpLibPath);
|
||||
}
|
||||
|
||||
if (curDir != NULL && curDir[0] != '\0' && strcmp(curDir, tmpLibPath) != 0)
|
||||
{
|
||||
strcat(libraryPath, ":");
|
||||
strcat(libraryPath, curDir);
|
||||
}
|
||||
|
||||
if (gameDir != NULL && gameDir[0] != '\0')
|
||||
{
|
||||
strcat(libraryPath, ":");
|
||||
strcat(libraryPath, gameDir);
|
||||
}
|
||||
|
||||
setenv(LD_LIBRARY_PATH, libraryPath, 1);
|
||||
|
||||
// Ensure the preload path is set correctly
|
||||
if (isFlatpak)
|
||||
setenv(LD_PRELOAD, PRELOAD_FILE_FLATPAK, 1);
|
||||
else if (strcmp(ldPreloadLibrary, "") != 0)
|
||||
setenv(LD_PRELOAD, ldPreloadLibrary, 1);
|
||||
if (strcmp(ldLibPath, "") != 0)
|
||||
setenv(LD_PRELOAD, ldLibPath, 1);
|
||||
else
|
||||
setenv(LD_PRELOAD, PRELOAD_FILE_NAME, 1);
|
||||
setenv(LD_PRELOAD, PRELOAD_FILE_NAME, 1); // Should not reach here
|
||||
|
||||
if (zink)
|
||||
setenv("MESA_LOADER_DRIVER_OVERRIDE", "zink", 1);
|
||||
@@ -401,6 +514,11 @@ void setEnvironmentVariables(int isFlatpak, int zink, int nvidia)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prints the usage information for the Lindbergh loader.
|
||||
*
|
||||
* This function displays the command-line options and usage instructions for
|
||||
* the Lindbergh loader.
|
||||
* @param argv The command-line arguments array.
|
||||
* Prints the usage for the loader
|
||||
*/
|
||||
void printUsage(char *argv[])
|
||||
@@ -416,10 +534,16 @@ void printUsage(char *argv[])
|
||||
printf(" --version Displays the version of the loader and team's names\n");
|
||||
printf(" --help Displays this usage text\n");
|
||||
printf(" --config | -c Specifies configuration path\n");
|
||||
printf(" --gamepath | -g Specifies game path\n");
|
||||
printf(" --gamepath | -g Specifies game path without ELF name\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lists available evdev controllers and their inputs.
|
||||
*
|
||||
* This function initializes the controller system and then iterates through
|
||||
* the available controllers, printing their names and the names of their
|
||||
* inputs.
|
||||
* @return EXIT_SUCCESS on success, EXIT_FAILURE on failure.
|
||||
* Lists available evdev controllers and their inputs
|
||||
*/
|
||||
int listControllers()
|
||||
@@ -453,8 +577,10 @@ int listControllers()
|
||||
}
|
||||
|
||||
/**
|
||||
* Small utility to automatically detect the game and run it without
|
||||
* having to type a long string in.
|
||||
* @brief Prints the version information of the Lindbergh loader.
|
||||
*
|
||||
* This function displays the version number of the Lindbergh loader and the
|
||||
* names of the team members.
|
||||
*/
|
||||
void printVersion() {
|
||||
printf("Lindbergh Loader v%d.%d\n", MAJOR_VERSION, MINOR_VERSION);
|
||||
@@ -467,7 +593,9 @@ void printVersion() {
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Check for --version before directory operations
|
||||
char gameELF[128] = {0};
|
||||
char gameDir[MAX_PATH_LEN] = {0};
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "--version") == 0) {
|
||||
printVersion();
|
||||
return EXIT_SUCCESS;
|
||||
@@ -483,151 +611,46 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
return listControllers();
|
||||
}
|
||||
|
||||
// We save the current dir to return to it later
|
||||
char curDir[MAX_PATH_LEN];
|
||||
if (getcwd(curDir, sizeof(curDir)) == NULL)
|
||||
{
|
||||
log_error("Error: could not get the current directory.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Check if a game folder was passed as a parameter
|
||||
char gamePath[PATH_MAX] = {0};
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "--gamepath") == 0)
|
||||
{
|
||||
if (i + 1 >= argc)
|
||||
{
|
||||
break;
|
||||
}
|
||||
strncpy(gamePath, argv[i + 1], PATH_MAX);
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the games
|
||||
struct dirent *ent;
|
||||
DIR *dir;
|
||||
|
||||
if (gamePath[0] != '\0')
|
||||
{
|
||||
// Check if the passed folder is valid
|
||||
if (!isValidDirectory(gamePath))
|
||||
{
|
||||
log_error("The game folder is invalid.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
dir = opendir(gamePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = opendir(curDir);
|
||||
}
|
||||
|
||||
if (dir == NULL)
|
||||
{
|
||||
log_error("Could not list files in current directory.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
char *game = NULL;
|
||||
|
||||
int lindberghSharedObjectFound = 0;
|
||||
int isFlatpak = 0;
|
||||
|
||||
while ((ent = readdir(dir)) != NULL)
|
||||
{
|
||||
|
||||
if (ent->d_type != DT_REG)
|
||||
continue;
|
||||
|
||||
if (strcmp(ent->d_name, PRELOAD_FILE_NAME) == 0)
|
||||
{
|
||||
lindberghSharedObjectFound = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
while (game == NULL)
|
||||
{
|
||||
if (strcmp(games[index], "END") == 0)
|
||||
break;
|
||||
|
||||
if (strcmp(ent->d_name, games[index]) == 0)
|
||||
{
|
||||
game = games[index];
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
if (game != NULL && lindberghSharedObjectFound)
|
||||
break;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
ldPreloadLibrary = findLDPreloadLibrary();
|
||||
|
||||
if (!lindberghSharedObjectFound)
|
||||
{
|
||||
FILE *file = fopen(PRELOAD_FILE_FLATPAK, "r");
|
||||
if (file)
|
||||
{
|
||||
fclose(file);
|
||||
isFlatpak = 1;
|
||||
}
|
||||
else if (strcmp(ldPreloadLibrary, "") == 0)
|
||||
{
|
||||
log_error("The preload object lindbergh.so was not found in this directory.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Build up the command to start the game
|
||||
|
||||
int testMode = 0;
|
||||
int gdb = 0;
|
||||
int zink = 0;
|
||||
int nvidia = 0;
|
||||
int forceGame = 0;
|
||||
int segaboot = 0;
|
||||
char extConfigPath[PATH_MAX] = {0};
|
||||
char forceGamePath[128] = {0};
|
||||
int testMode = false;
|
||||
int gdb = false;
|
||||
int zink = false;
|
||||
int nvidia = false;
|
||||
int forceGame = false;
|
||||
int segaboot = false;
|
||||
char *extConfigPath = NULL;
|
||||
char *passedGamePath = NULL;
|
||||
char *forcedGamePath = NULL;
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--test") == 0)
|
||||
{
|
||||
testMode = 1;
|
||||
testMode = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--segaboot") == 0)
|
||||
{
|
||||
segaboot = 1;
|
||||
segaboot = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[i], "--gdb") == 0)
|
||||
{
|
||||
gdb = 1;
|
||||
gdb = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[i], "-z") == 0 || strcmp(argv[i], "--zink") == 0)
|
||||
{
|
||||
zink = 1;
|
||||
zink = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--nvidia") == 0)
|
||||
{
|
||||
nvidia = 1;
|
||||
nvidia = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -637,7 +660,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
break;
|
||||
}
|
||||
strncpy(extConfigPath, argv[i + 1], PATH_MAX);
|
||||
extConfigPath = strdup(argv[i + 1]);
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
@@ -645,46 +668,153 @@ int main(int argc, char *argv[])
|
||||
if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "--gamepath") == 0)
|
||||
{
|
||||
if (i + 1 >= argc)
|
||||
{
|
||||
break;
|
||||
}
|
||||
passedGamePath = strdup(argv[i + 1]);
|
||||
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Treat the argument as the game name
|
||||
strcpy(forceGamePath, argv[i]);
|
||||
forceGame = 1;
|
||||
forcedGamePath = strdup(argv[i]);
|
||||
forceGame = true;
|
||||
}
|
||||
|
||||
// We save the current dir to return to it later
|
||||
char curDir[MAX_PATH_LEN];
|
||||
if (getcwd(curDir, sizeof(curDir)) == NULL)
|
||||
{
|
||||
log_error("Error: could not get the current directory.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
char command[PATH_MAX] = {0};
|
||||
char *forcedGameDir;
|
||||
char *forcedGameElf;
|
||||
if (forceGame)
|
||||
{
|
||||
if (forcedGamePath != NULL)
|
||||
{
|
||||
forcedGameDir = dirname(strdup(forcedGamePath));
|
||||
forcedGameElf = basename(strdup(forcedGamePath));
|
||||
|
||||
if (strcmp(forcedGameDir, ".") == 0) // Only the ELF file name was passed.
|
||||
{
|
||||
if (passedGamePath[0] != '\0')
|
||||
snprintf(gameDir, MAX_PATH_LEN, "%s", passedGamePath);
|
||||
else
|
||||
snprintf(gameDir, MAX_PATH_LEN, "./");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (passedGamePath != NULL) // ELF with path and also -g option pointing to a folder
|
||||
log_warn("Warning: elf passed with a path, and -g option enabled. Ignoring -g option.");
|
||||
|
||||
snprintf(gameDir, MAX_PATH_LEN, "%s", forcedGameDir);
|
||||
}
|
||||
|
||||
if (strcmp(forcedGameElf, ".") != 0)
|
||||
strcpy(gameELF, forcedGameElf);
|
||||
// Check if the passed folder is valid
|
||||
if (!isValidDirectory(gameDir))
|
||||
{
|
||||
log_error("%s is not a valid directory here.", gameDir);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Look for the game ELF's
|
||||
struct dirent *ent;
|
||||
DIR *dir;
|
||||
|
||||
if (passedGamePath != NULL && passedGamePath[0] != '\0')
|
||||
{
|
||||
snprintf(gameDir, MAX_PATH_LEN, "%s", passedGamePath);
|
||||
|
||||
// Check if the passed folder is valid
|
||||
if (!isValidDirectory(gameDir))
|
||||
{
|
||||
log_error("%s is not a valid directory.", gameDir);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
dir = opendir(gameDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(gameDir, MAX_PATH_LEN, "%s", curDir);
|
||||
dir = opendir(curDir);
|
||||
}
|
||||
|
||||
if (dir == NULL)
|
||||
{
|
||||
log_error("Could not list files in current directory.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
while ((ent = readdir(dir)) != NULL)
|
||||
{
|
||||
if (ent->d_type != DT_REG)
|
||||
continue;
|
||||
|
||||
int index = 0;
|
||||
while (!found)
|
||||
{
|
||||
if (strcmp(games[index], "END") == 0)
|
||||
break;
|
||||
|
||||
if (strcmp(ent->d_name, games[index]) == 0)
|
||||
{
|
||||
strcpy(gameELF, games[index]);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
if (segaboot)
|
||||
{
|
||||
strcpy(gameELF, "segaboot");
|
||||
testMode = true;
|
||||
}
|
||||
|
||||
if (gameELF[0] == '\0')
|
||||
{
|
||||
log_error("No lindbergh game found in this directory.");
|
||||
printUsage(argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
sprintf(command, "\"%s/\"%s", gameDir, gameELF);
|
||||
|
||||
char *ldPreloadLibrary = findLDPreloadLibrary();
|
||||
|
||||
if (strcmp(ldPreloadLibrary, PRELOAD_FILE_NAME) == 0)
|
||||
{
|
||||
char lindberghSoPath[MAX_PATH_LEN];
|
||||
if (gameDir[0] != '\0')
|
||||
snprintf(lindberghSoPath, strlen(gameDir) + sizeof(PRELOAD_FILE_NAME) + 1, "%s/%s", gameDir, PRELOAD_FILE_NAME);
|
||||
|
||||
if (access(lindberghSoPath, F_OK) != 0)
|
||||
{
|
||||
log_error("The preload object lindbergh.so was not found.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ldPreloadLibrary = strdup(lindberghSoPath);
|
||||
}
|
||||
|
||||
// Ensure environment variables are set correctly
|
||||
setEnvironmentVariables(isFlatpak, zink, nvidia);
|
||||
|
||||
char command[128] = {0};
|
||||
if (gamePath[0] != '\0')
|
||||
sprintf(command, "\"%s\"/", gamePath);
|
||||
else
|
||||
strcpy(command, "./");
|
||||
|
||||
if (forceGame)
|
||||
{
|
||||
strcat(command, forceGamePath);
|
||||
}
|
||||
else if (segaboot)
|
||||
{
|
||||
strcat(command, "segaboot -t");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (game == NULL)
|
||||
{
|
||||
log_error("No lindbergh game found in this directory.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
strcat(command, game);
|
||||
}
|
||||
setEnvironmentVariables(ldPreloadLibrary, curDir, gameDir, zink, nvidia);
|
||||
|
||||
if (testMode)
|
||||
testModePath(command);
|
||||
|
||||
isCleanElf(command);
|
||||
|
||||
if (gdb)
|
||||
@@ -695,16 +825,16 @@ int main(int argc, char *argv[])
|
||||
strcpy(command, temp);
|
||||
}
|
||||
|
||||
if (extConfigPath[0] != '\0')
|
||||
if (extConfigPath != NULL && extConfigPath[0] != '\0')
|
||||
{
|
||||
setenv(LINDBERGH_CONFIG_PATH, extConfigPath, 1);
|
||||
}
|
||||
|
||||
log_info("Starting $ %s", command);
|
||||
|
||||
if (gamePath[0] != '\0')
|
||||
if (gameDir[0] != '\0')
|
||||
{
|
||||
if (chdir(gamePath) != 0)
|
||||
if (chdir(gameDir) != 0)
|
||||
{
|
||||
log_error("Could not change to game path.");
|
||||
return EXIT_FAILURE;
|
||||
@@ -712,7 +842,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
int sysCmd = system(command);
|
||||
|
||||
if (gamePath[0] != '\0')
|
||||
if (gameDir[0] != '\0')
|
||||
{
|
||||
if (chdir(curDir) != 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user