Merge pull request #84 from dkeruza-neo/master

Stand alone lindbergh loader
This commit is contained in:
dkeruza
2025-04-05 17:45:30 -04:00
committed by GitHub
2 changed files with 394 additions and 261 deletions
+4 -1
View File
@@ -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
View File
@@ -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)
{