Compare commits

...
5 Commits
Author SHA1 Message Date
dkeruza a374dec081 Merge pull request #80 from lindbergh-loader/neo-pr-test
Fixed main.yml
2025-04-01 18:51:38 -04:00
dkeruza-neo d1c98e6a7f Fixed main.yml 2025-04-01 18:48:05 -04:00
dkeruza 1ade940d2f Merge pull request #79 from lindbergh-loader/neo-pr-test
Improved Distro detection function.
2025-04-01 18:41:46 -04:00
dkeruza-neo 2e2a2b4052 lindbergh can run games in a different folder than current. 2025-04-01 18:39:49 -04:00
dkeruza-neo 23152f5788 Improved Distro detection function. 2025-04-01 16:42:43 -04:00
4 changed files with 245 additions and 27 deletions
+2
View File
@@ -3,6 +3,8 @@ name: Automated Builds
on: on:
workflow_dispatch: workflow_dispatch:
pull_request: pull_request:
branches:
- master
paths-ignore: paths-ignore:
- '**.md' - '**.md'
- '.github/ISSUE_TEMPLATE/*' - '.github/ISSUE_TEMPLATE/*'
+6
View File
@@ -2,6 +2,12 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [2.0.7]
### Added
- Option -g | --gamepath to lindbergh to point to games in a different folder.
- lindbergh elf searches for lindbergh.so in common library folders ("/usr/lib/i386-linux-gnu", "/usr/lib32", etc).
- Improved Distro detection function to inform that the Distro is not based on Debian.
## [2.0.6] ## [2.0.6]
### Fixed ### Fixed
- Reverted (Fixed LGJ, VT3 and ID4/ID5 JVS passthrough). - Reverted (Fixed LGJ, VT3 and ID4/ID5 JVS passthrough).
+58 -19
View File
@@ -177,32 +177,76 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr)
} }
} }
char *checkIDlike() char *trimOS_ID(char *str)
{ {
FILE *file = fopen("/etc/os-release", "r"); if (!str)
if (!file) return str;
char *end;
while (isspace((unsigned char)*str) || *str == '"' || *str == '\'')
str++;
if (*str == 0)
return str;
end = str + strlen(str) - 1;
while (end > str && (isspace((unsigned char)*end) || *end == '"' || *end == '\''))
end--;
*(end + 1) = '\0';
return str;
}
bool checkOS_ID()
{
FILE *fp = fopen("/etc/os-release", "r");
if (!fp)
{ {
perror("Failed to open /etc/os-release"); return false;
return NULL;
} }
char line[256]; char line[256];
char *result = NULL; bool found = false;
while (fgets(line, sizeof(line), file)) while (fgets(line, sizeof(line), fp))
{ {
if (strncmp(line, "ID_LIKE=", 8) == 0) if (strncmp(line, "ID=", 3) == 0)
{ {
char *id_like = strchr(line, '='); char *value = trimOS_ID(line + 3);
if (id_like) if (strcmp(value, "debian") == 0 || strcmp(value, "ubuntu") == 0)
{ {
result = strdup(id_like); found = true;
break; break;
} }
} }
else if (strncmp(line, "ID_LIKE=", 8) == 0)
{
char value_part[256];
strncpy(value_part, line + 8, sizeof(value_part) - 1);
value_part[sizeof(value_part) - 1] = '\0';
char *value_trimmed = trimOS_ID(value_part);
char *token = strtok(value_trimmed, " \t\n");
while (token != NULL)
{
char *clean_token = trimOS_ID(token);
if (strcmp(clean_token, "debian") == 0 || strcmp(clean_token, "ubuntu") == 0)
{
found = true;
break;
}
token = strtok(NULL, " \t\n");
}
if (found)
break;
}
} }
fclose(file);
return result; fclose(fp);
return found;
} }
void __attribute__((constructor)) hook_init() void __attribute__((constructor)) hook_init()
@@ -221,12 +265,7 @@ void __attribute__((constructor)) hook_init()
gId = getConfig()->crc32; gId = getConfig()->crc32;
char *id_like = checkIDlike(); if (!checkOS_ID())
if (id_like == NULL)
{
log_warn("Unable to get system info on current OS");
}
else if (strstr(id_like, "debian") == NULL)
{ {
log_warn("Seems like you're not in debian-like system. There might be unexpected issues."); log_warn("Seems like you're not in debian-like system. There might be unexpected issues.");
} }
+179 -8
View File
@@ -1,8 +1,12 @@
#include <dirent.h> #include <dirent.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "evdevinput.h" #include "evdevinput.h"
#include "version.h" #include "version.h"
@@ -14,8 +18,10 @@
#define PRELOAD_FILE_FLATPAK "/app/lib32/lindbergh.so" #define PRELOAD_FILE_FLATPAK "/app/lib32/lindbergh.so"
#define TEAM "bobbydilley, retrofan, dkeruza-neo, doozer, francesco, rolel, caviar-x" #define TEAM "bobbydilley, retrofan, dkeruza-neo, doozer, francesco, rolel, caviar-x"
#define LINDBERGH_CONFIG_PATH "LINDBERGH_CONFIG_PATH" #define LINDBERGH_CONFIG_PATH "LINDBERGH_CONFIG_PATH"
#define MAX_PATH_LEN 1024
uint32_t elf_crc = 0; uint32_t elf_crc = 0;
char *ldPreloadLibrary = "";
// List of all lindbergh executables known, not including the test executables // List of all lindbergh executables known, not including the test executables
char *games[] = {"main.exe", char *games[] = {"main.exe",
@@ -231,6 +237,95 @@ void testModePath(char *name)
strcat(name, " -t"); strcat(name, " -t");
} }
bool isValidDirectory(const char *path)
{
struct stat statbuf;
if (stat(path, &statbuf) != 0)
return false;
return S_ISDIR(statbuf.st_mode);
}
char *find32bLibFolder(void)
{
const char *candidates[] = {"lib32", "lib/i386-linux-gnu", "lib/i686-linux-gnu", "lib"};
int num_candidates = sizeof(candidates) / sizeof(candidates[0]);
char current_path[PATH_MAX];
struct stat st;
char *result_path = NULL;
for (int i = 0; i < num_candidates; ++i)
{
int written = snprintf(current_path, sizeof(current_path), "/usr/%s", candidates[i]);
if (written < 0 || (size_t)written >= sizeof(current_path))
continue;
if (stat(current_path, &st) == 0 && S_ISDIR(st.st_mode))
{
size_t path_len = strlen(current_path);
result_path = (char *)malloc(path_len + 1);
if (result_path == NULL)
{
log_fatal("Failed to allocate memory for result path.");
return NULL;
}
strcpy(result_path, current_path);
return result_path;
}
}
return NULL;
}
char *findLDPreloadLibrary()
{
const char *library_name = PRELOAD_FILE_NAME;
static char *empty_string = "";
char *found_path_ptr = NULL;
char *search_dir = find32bLibFolder();
if (search_dir == NULL || search_dir[0] == '\0')
{
log_error("Error: search_dir is NULL or empty.\n");
return empty_string;
}
char full_library_path[PATH_MAX];
int len_written = snprintf(full_library_path, sizeof(full_library_path), "%s/%s", search_dir, library_name);
if (len_written < 0 || (size_t)len_written >= sizeof(full_library_path))
{
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;
}
if (access(full_library_path, F_OK) == 0)
{
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;
}
else
{
strcpy(found_path_ptr, full_library_path);
return found_path_ptr;
}
}
else
{
return empty_string;
}
}
/** /**
* Makes sure the environment variables are set correctly * Makes sure the environment variables are set correctly
* to run the game. * to run the game.
@@ -252,10 +347,12 @@ void setEnvironmentVariables(int isFlatpak, int zink, int nvidia)
setenv(LD_LIBRARY_PATH, libraryPath, 1); setenv(LD_LIBRARY_PATH, libraryPath, 1);
// Ensure the preload path is set correctly // Ensure the preload path is set correctly
if (!isFlatpak) if (isFlatpak)
setenv(LD_PRELOAD, PRELOAD_FILE_NAME, 1);
else
setenv(LD_PRELOAD, PRELOAD_FILE_FLATPAK, 1); setenv(LD_PRELOAD, PRELOAD_FILE_FLATPAK, 1);
else if (strcmp(ldPreloadLibrary, "") != 0)
setenv(LD_PRELOAD, ldPreloadLibrary, 1);
else
setenv(LD_PRELOAD, PRELOAD_FILE_NAME, 1);
if (zink) if (zink)
setenv("MESA_LOADER_DRIVER_OVERRIDE", "zink", 1); setenv("MESA_LOADER_DRIVER_OVERRIDE", "zink", 1);
@@ -283,6 +380,7 @@ void printUsage(char *argv[])
printf(" --version Displays the version of the loader and team's names\n"); printf(" --version Displays the version of the loader and team's names\n");
printf(" --help Displays this usage text\n"); printf(" --help Displays this usage text\n");
printf(" --config | -c Specifies configuration path\n"); printf(" --config | -c Specifies configuration path\n");
printf(" --gamepath | -g Specifies game path\n");
} }
/** /**
@@ -339,9 +437,48 @@ int main(int argc, char *argv[])
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
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 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;
}
}
// Check if the passed folder is valid
if (!isValidDirectory(gamePath))
{
log_error("The game folder is invalid.");
return EXIT_FAILURE;
}
// Look for the games // Look for the games
struct dirent *ent; struct dirent *ent;
DIR *dir = opendir("."); DIR *dir;
if (gamePath[0] != '\0')
{
dir = opendir(gamePath);
}
else
{
dir = opendir(curDir);
}
if (dir == NULL) if (dir == NULL)
{ {
@@ -398,6 +535,8 @@ int main(int argc, char *argv[])
return listControllers(); return listControllers();
} }
ldPreloadLibrary = findLDPreloadLibrary();
if (!lindberghSharedObjectFound) if (!lindberghSharedObjectFound)
{ {
FILE *file = fopen(PRELOAD_FILE_FLATPAK, "r"); FILE *file = fopen(PRELOAD_FILE_FLATPAK, "r");
@@ -406,7 +545,7 @@ int main(int argc, char *argv[])
fclose(file); fclose(file);
isFlatpak = 1; isFlatpak = 1;
} }
else else if (strcmp(ldPreloadLibrary, "") == 0)
{ {
log_error("The preload object lindbergh.so was not found in this directory."); log_error("The preload object lindbergh.so was not found in this directory.");
return EXIT_FAILURE; return EXIT_FAILURE;
@@ -466,6 +605,15 @@ int main(int argc, char *argv[])
i += 1; i += 1;
continue; continue;
} }
if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "--gamepath") == 0)
{
if (i + 1 >= argc)
break;
i += 1;
continue;
}
// Treat the argument as the game name // Treat the argument as the game name
strcpy(forceGamePath, argv[i]); strcpy(forceGamePath, argv[i]);
forceGame = 1; forceGame = 1;
@@ -475,14 +623,18 @@ int main(int argc, char *argv[])
setEnvironmentVariables(isFlatpak, zink, nvidia); setEnvironmentVariables(isFlatpak, zink, nvidia);
char command[128] = {0}; char command[128] = {0};
strcpy(command, "./"); if (gamePath[0] != '\0')
sprintf(command, "%s/", gamePath);
else
strcpy(command, "./");
if (forceGame) if (forceGame)
{ {
strcat(command, forceGamePath); strcat(command, forceGamePath);
} }
else if (segaboot) else if (segaboot)
{ {
strcat(command, "segaboot -t"); strcat(command, "segaboot -t");
} }
else else
{ {
@@ -514,5 +666,24 @@ int main(int argc, char *argv[])
log_info("Starting $ %s", command); log_info("Starting $ %s", command);
return system(command); if (gamePath[0] != '\0')
{
if (chdir(gamePath) != 0)
{
log_error("Could not change to game path.");
return EXIT_FAILURE;
}
}
int sysCmd = system(command);
if (gamePath[0] != '\0')
{
if (chdir(curDir) != 0)
{
log_error("Could not return to the original directory.");
return EXIT_FAILURE;
}
}
return sysCmd;
} }