DarkflameServer/dCommon/BinaryPathFinder.cpp
Jonathan Romano f8f5b731f1
Allow servers to be run from directories other than build. Read/write files relative to binary instead of cwd (#834)
Allows the server to be run from a non-build directory.  Also only read or write files relative to the build directory, regardless of where the server is run from
2022-11-27 03:59:59 -08:00

72 lines
2.3 KiB
C++

#include <filesystem>
#include <string>
#include "BinaryPathFinder.h"
#include "dPlatforms.h"
#if defined(DARKFLAME_PLATFORM_WIN32)
#include <Windows.h>
#elif defined(DARKFLAME_PLATFORM_MACOS) || defined(DARKFLAME_PLATFORM_IOS)
#include <mach-o/dyld.h>
#elif defined(DARKFLAME_PLATFORM_FREEBSD)
#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdlib.h>
#endif
std::filesystem::path BinaryPathFinder::binaryDir;
std::filesystem::path BinaryPathFinder::GetBinaryDir() {
if (!binaryDir.empty()) {
return binaryDir;
}
std::string pathStr;
// Derived from boost::dll::program_location, licensed under the Boost Software License: http://www.boost.org/LICENSE_1_0.txt
#if defined(DARKFLAME_PLATFORM_WIN32)
char path[MAX_PATH];
GetModuleFileName(NULL, path, MAX_PATH);
pathStr = std::string(path);
#elif defined(DARKFLAME_PLATFORM_MACOS) || defined(DARKFLAME_PLATFORM_IOS)
char path[1024];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0) {
pathStr = std::string(path);
} else {
// The filepath size is greater than our initial buffer size, so try again with the size
// that _NSGetExecutablePath told us it actually is
char *p = new char[size];
if (_NSGetExecutablePath(p, &size) != 0) {
throw std::runtime_error("Failed to get binary path from _NSGetExecutablePath");
}
pathStr = std::string(p);
delete[] p;
}
#elif defined(DARKFLAME_PLATFORM_FREEBSD)
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
char buf[10240];
size_t cb = sizeof(buf);
sysctl(mib, 4, buf, &cb, NULL, 0);
pathStr = std::string(buf);
#else // DARKFLAME_PLATFORM_LINUX || DARKFLAME_PLATFORM_UNIX || DARKFLAME_PLATFORM_ANDROID
pathStr = std::filesystem::read_symlink("/proc/self/exe");
#endif
// Some methods like _NSGetExecutablePath could return a symlink
// Either way, we need to get the parent path because we want the directory, not the binary itself
// We also ensure that it is an absolute path so that it is valid if we need to construct a path
// to exucute on unix systems (eg sudo BinaryPathFinder::GetBinaryDir() / WorldServer)
if (std::filesystem::is_symlink(pathStr)) {
binaryDir = std::filesystem::absolute(std::filesystem::read_symlink(pathStr).parent_path());
} else {
binaryDir = std::filesystem::absolute(std::filesystem::path(pathStr).parent_path());
}
return binaryDir;
}