Change to execution paths to binary paths (#200)

Previously, it used argv[0] for the execution path, which is fine in
most cases, but in my case, it is not.
The thing is, I use NixOS, and I have created a Nix module for BeamMP.
When running BeamMP-Launcher, it tries to check for updates, and fails
because of the SHA hash.
There are other ways around this, such as setting the execution
directory, but I think this is a far clearer approach

---

By creating this pull request, I understand that code that is AI
generated or otherwise automatically generated may be rejected without
further discussion.
I declare that I fully understand all code I pushed into this PR, and
wrote all this code myself and own the rights to this code.
This commit is contained in:
Tixx 2025-08-02 19:38:18 +02:00 committed by GitHub
commit 5b2eb0a1a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 47 additions and 15 deletions

View File

@ -13,6 +13,7 @@
void InitLauncher(); void InitLauncher();
beammp_fs_string GetEP(const beammp_fs_char* P = nullptr); beammp_fs_string GetEP(const beammp_fs_char* P = nullptr);
std::filesystem::path GetBP(const beammp_fs_char* P = nullptr);
std::filesystem::path GetGamePath(); std::filesystem::path GetGamePath();
std::string GetVer(); std::string GetVer();
std::string GetPatch(); std::string GetPatch();

View File

@ -236,7 +236,7 @@ namespace Utils {
for (size_t i = 0; i < sha256_len; i++) { for (size_t i = 0; i < sha256_len; i++) {
char buf[3]; char buf[3];
sprintf(buf, "%02x", sha256_value[i]); sprintf(buf, "%02x", sha256_value[i]);
buf[2] = NULL; buf[2] = '\0';
result += buf; result += buf;
} }
return result; return result;
@ -280,7 +280,7 @@ namespace Utils {
for (size_t i = 0; i < sha256_len; i++) { for (size_t i = 0; i < sha256_len; i++) {
char buf[3]; char buf[3];
sprintf(buf, "%02x", sha256_value[i]); sprintf(buf, "%02x", sha256_value[i]);
buf[2] = NULL; buf[2] = '\0';
result += buf; result += buf;
} }
return result; return result;

View File

@ -14,7 +14,10 @@
#if defined(_WIN32) #if defined(_WIN32)
#elif defined(__linux__) #elif defined(__linux__)
#include <unistd.h> #include <unistd.h>
#endif #elif defined (__APPLE__)
#include <unistd.h>
#include <libproc.h>
#endif // __APPLE__
#include "Http.h" #include "Http.h"
#include "Logger.h" #include "Logger.h"
#include "Network/network.hpp" #include "Network/network.hpp"
@ -94,6 +97,34 @@ beammp_fs_string GetEP(const beammp_fs_char* P) {
}(); }();
return Ret; return Ret;
} }
fs::path GetBP(const beammp_fs_char* P) {
fs::path fspath = {};
#if defined(_WIN32)
beammp_fs_char path[256];
GetModuleFileNameW(nullptr, path, sizeof(path));
fspath = path;
#elif defined(__linux__)
fspath = fs::canonical("/proc/self/exe");
#elif defined(__APPLE__)
pid_t pid = getpid();
char path[PROC_PIDPATHINFO_MAXSIZE];
// While this is fine for a raw executable,
// an application bundle is read-only and these files
// should instead be placed in Application Support.
proc_pidpath(pid, path, sizeof(path));
fspath = std::string(path);
#else
fspath = beammp_fs_string(P);
#endif
fspath = fs::weakly_canonical(fspath.string() + "/..");
#if defined(_WIN32)
return fspath.wstring();
#else
return fspath.string();
#endif
}
#if defined(_WIN32) #if defined(_WIN32)
void ReLaunch() { void ReLaunch() {
std::wstring Arg; std::wstring Arg;
@ -103,7 +134,7 @@ void ReLaunch() {
} }
info("Relaunch!"); info("Relaunch!");
system("cls"); system("cls");
ShellExecuteW(nullptr, L"runas", (GetEP() + GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL); ShellExecuteW(nullptr, L"runas", (GetBP() / GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL);
ShowWindow(GetConsoleWindow(), 0); ShowWindow(GetConsoleWindow(), 0);
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
exit(1); exit(1);
@ -114,7 +145,7 @@ void URelaunch() {
Arg += Utils::ToWString(options.argv[c - 1]); Arg += Utils::ToWString(options.argv[c - 1]);
Arg += L" "; Arg += L" ";
} }
ShellExecuteW(nullptr, L"open", (GetEP() + GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL); ShellExecuteW(nullptr, L"open", (GetBP() / GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL);
ShowWindow(GetConsoleWindow(), 0); ShowWindow(GetConsoleWindow(), 0);
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
exit(1); exit(1);
@ -128,7 +159,7 @@ void ReLaunch() {
} }
info("Relaunch!"); info("Relaunch!");
system("clear"); system("clear");
int ret = execv(options.executable_name.c_str(), const_cast<char**>(options.argv)); int ret = execv((GetBP() / GetEN()).c_str(), const_cast<char**>(options.argv));
if (ret < 0) { if (ret < 0) {
error(std::string("execv() failed with: ") + strerror(errno) + ". Failed to relaunch"); error(std::string("execv() failed with: ") + strerror(errno) + ". Failed to relaunch");
exit(1); exit(1);
@ -137,7 +168,7 @@ void ReLaunch() {
exit(1); exit(1);
} }
void URelaunch() { void URelaunch() {
int ret = execv(options.executable_name.c_str(), const_cast<char**>(options.argv)); int ret = execv((GetBP() / GetEN()).c_str(), const_cast<char**>(options.argv));
if (ret < 0) { if (ret < 0) {
error(std::string("execv() failed with: ") + strerror(errno) + ". Failed to relaunch"); error(std::string("execv() failed with: ") + strerror(errno) + ". Failed to relaunch");
exit(1); exit(1);
@ -169,9 +200,9 @@ void CheckForUpdates(const std::string& CV) {
"https://backend.beammp.com/version/launcher?branch=" + Branch + "&pk=" + PublicKey); "https://backend.beammp.com/version/launcher?branch=" + Branch + "&pk=" + PublicKey);
transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower); transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower);
beammp_fs_string EP(GetEP() + GetEN()), Back(GetEP() + beammp_wide("BeamMP-Launcher.back")); beammp_fs_string BP(GetBP() / GetEN()), Back(GetBP() / beammp_wide("BeamMP-Launcher.back"));
std::string FileHash = Utils::GetSha256HashReallyFastFile(EP); std::string FileHash = Utils::GetSha256HashReallyFastFile(BP);
if (FileHash != LatestHash && IsOutdated(Version(VersionStrToInts(GetVer() + GetPatch())), Version(VersionStrToInts(LatestVersion)))) { if (FileHash != LatestHash && IsOutdated(Version(VersionStrToInts(GetVer() + GetPatch())), Version(VersionStrToInts(LatestVersion)))) {
if (!options.no_update) { if (!options.no_update) {
@ -184,16 +215,16 @@ void CheckForUpdates(const std::string& CV) {
"https://backend.beammp.com/builds/launcher?download=true" "https://backend.beammp.com/builds/launcher?download=true"
"&pk=" "&pk="
+ PublicKey + "&branch=" + Branch, + PublicKey + "&branch=" + Branch,
beammp_wide("new_") + EP, LatestHash); beammp_wide("new_") + BP, LatestHash);
std::error_code ec; std::error_code ec;
fs::remove(Back, ec); fs::remove(Back, ec);
if (ec == std::errc::permission_denied) { if (ec == std::errc::permission_denied) {
error("Failed to remove old backup file: " + ec.message() + ". Using alternative name."); error("Failed to remove old backup file: " + ec.message() + ". Using alternative name.");
fs::rename(EP, Back + beammp_wide(".") + Utils::ToWString(FileHash.substr(0, 8))); fs::rename(BP, Back + beammp_wide(".") + Utils::ToWString(FileHash.substr(0, 8)));
} else { } else {
fs::rename(EP, Back); fs::rename(BP, Back);
} }
fs::rename(beammp_wide("new_") + EP, EP); fs::rename(beammp_wide("new_") + BP, BP);
URelaunch(); URelaunch();
#endif #endif
} else { } else {
@ -254,8 +285,8 @@ void InitLauncher() {
} }
#endif #endif
size_t DirCount(const std::filesystem::path& path) { size_t DirCount(const fs::path& path) {
return (size_t)std::distance(std::filesystem::directory_iterator { path }, std::filesystem::directory_iterator {}); return (size_t)std::distance(fs::directory_iterator { path }, fs::directory_iterator {});
} }
void CheckMP(const beammp_fs_string& Path) { void CheckMP(const beammp_fs_string& Path) {