diff --git a/Data/ThunksDB.json b/Data/ThunksDB.json index c3e88ec42..00a307af9 100644 --- a/Data/ThunksDB.json +++ b/Data/ThunksDB.json @@ -6,10 +6,10 @@ "X11" ], "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libGL.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libGL.so.1", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libGL.so.1.2.0", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libGL.so.1.7.0" + "@PREFIX_LIB@/libGL.so", + "@PREFIX_LIB@/libGL.so.1", + "@PREFIX_LIB@/libGL.so.1.2.0", + "@PREFIX_LIB@/libGL.so.1.7.0" ] }, "GLESv2": { @@ -18,17 +18,17 @@ "X11" ], "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libGLESv2.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libGLESv2.so.2", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libGLESv2.so.2.0.0" + "@PREFIX_LIB@/libGLESv2.so", + "@PREFIX_LIB@/libGLESv2.so.2", + "@PREFIX_LIB@/libGLESv2.so.2.0.0" ] }, "X11": { "Library": "libX11-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libX11.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libX11.so.6", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libX11.so.6.4.0" + "@PREFIX_LIB@/libX11.so", + "@PREFIX_LIB@/libX11.so.6", + "@PREFIX_LIB@/libX11.so.6.4.0" ] }, "Vulkan": { @@ -37,8 +37,8 @@ "xcb" ], "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libvulkan.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libvulkan.so.1", + "@PREFIX_LIB@/libvulkan.so", + "@PREFIX_LIB@/libvulkan.so.1", "@HOME@/.local/share/Steam/ubuntu12_32/steam-runtime/pinned_libs_64/libvulkan.so.1" ], "Comment": [ @@ -48,137 +48,137 @@ "xcb": { "Library": "libxcb-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb.so.1", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb.so.1.1.0" + "@PREFIX_LIB@/libxcb.so", + "@PREFIX_LIB@/libxcb.so.1", + "@PREFIX_LIB@/libxcb.so.1.1.0" ] }, "xcb-dri2": { "Library": "libxcb-dri2-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-dri2.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-dri2.so.0", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-dri2.so.0.0.0" + "@PREFIX_LIB@/libxcb-dri2.so", + "@PREFIX_LIB@/libxcb-dri2.so.0", + "@PREFIX_LIB@/libxcb-dri2.so.0.0.0" ] }, "xcb-dri3": { "Library": "libxcb-dri3-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-dri3.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-dri3.so.0", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-dri3.so.0.0.0" + "@PREFIX_LIB@/libxcb-dri3.so", + "@PREFIX_LIB@/libxcb-dri3.so.0", + "@PREFIX_LIB@/libxcb-dri3.so.0.0.0" ] }, "xcb-xfixes": { "Library": "libxcb-xfixes-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-xfixes.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-xfixes.so.0", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-xfixes.so.0.0.0" + "@PREFIX_LIB@/libxcb-xfixes.so", + "@PREFIX_LIB@/libxcb-xfixes.so.0", + "@PREFIX_LIB@/libxcb-xfixes.so.0.0.0" ] }, "xcb-shm": { "Library": "libxcb-shm-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-shm.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-shm.so.0", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-shm.so.0.0.0" + "@PREFIX_LIB@/libxcb-shm.so", + "@PREFIX_LIB@/libxcb-shm.so.0", + "@PREFIX_LIB@/libxcb-shm.so.0.0.0" ] }, "xcb-sync": { "Library": "libxcb-sync-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-sync.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-sync.so.1", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-sync.so.1.0.0" + "@PREFIX_LIB@/libxcb-sync.so", + "@PREFIX_LIB@/libxcb-sync.so.1", + "@PREFIX_LIB@/libxcb-sync.so.1.0.0" ] }, "xcb-randr": { "Library": "libxcb-randr-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-randr.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-randr.so.0", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-randr.so.0.1.0" + "@PREFIX_LIB@/libxcb-randr.so", + "@PREFIX_LIB@/libxcb-randr.so.0", + "@PREFIX_LIB@/libxcb-randr.so.0.1.0" ] }, "xcb-present": { "Library": "libxcb-present-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-present.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-present.so.0", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-present.so.0.0.0" + "@PREFIX_LIB@/libxcb-present.so", + "@PREFIX_LIB@/libxcb-present.so.0", + "@PREFIX_LIB@/libxcb-present.so.0.0.0" ] }, "xcb-glx": { "Library": "libxcb-glx-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-glx.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-glx.so.0", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxcb-glx.so.0.0.0" + "@PREFIX_LIB@/libxcb-glx.so", + "@PREFIX_LIB@/libxcb-glx.so.0", + "@PREFIX_LIB@/libxcb-glx.so.0.0.0" ] }, "xshmfence": { "Library": "libxshmfence-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxshmfence.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxshmfence.so.1", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libxshmfence.so.1.0.0" + "@PREFIX_LIB@/libxshmfence.so", + "@PREFIX_LIB@/libxshmfence.so.1", + "@PREFIX_LIB@/libxshmfence.so.1.0.0" ] }, "drm": { "Library": "libdrm-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libdrm.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libdrm.so.2", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libdrm.so.2.4.0" + "@PREFIX_LIB@/libdrm.so", + "@PREFIX_LIB@/libdrm.so.2", + "@PREFIX_LIB@/libdrm.so.2.4.0" ] }, "asound": { "Library": "libasound-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libasound.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libasound.so.2", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libasound.so.2.0.0" + "@PREFIX_LIB@/libasound.so", + "@PREFIX_LIB@/libasound.so.2", + "@PREFIX_LIB@/libasound.so.2.0.0" ] }, "Xrender": { "Library": "libXrender-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libXrender.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libXrender.so.1", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libXrender.so.1.3.0" + "@PREFIX_LIB@/libXrender.so", + "@PREFIX_LIB@/libXrender.so.1", + "@PREFIX_LIB@/libXrender.so.1.3.0" ] }, "Xext": { "Library": "libXext-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libXext.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libXext.so.6", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libXext.so.6.4.0" + "@PREFIX_LIB@/libXext.so", + "@PREFIX_LIB@/libXext.so.6", + "@PREFIX_LIB@/libXext.so.6.4.0" ] }, "Xfixes": { "Library": "libXfixes-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libXfixes.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libXfixes.so.3", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libXfixes.so.3.1.0" + "@PREFIX_LIB@/libXfixes.so", + "@PREFIX_LIB@/libXfixes.so.3", + "@PREFIX_LIB@/libXfixes.so.3.1.0" ] }, "OpenCL": { "Library" : "libOpenCL-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libOpenCL.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libOpenCL.so.1", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libOpenCL.so.1.0.0" + "@PREFIX_LIB@/libOpenCL.so", + "@PREFIX_LIB@/libOpenCL.so.1", + "@PREFIX_LIB@/libOpenCL.so.1.0.0" ] }, "WaylandClient": { "Library" : "libwayland-client-guest.so", "Overlay": [ - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libwayland-client.so", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libwayland-client.so.0", - "@PREFIX_LIB@/@PREFIX_ARCH@-linux-gnu/libwayland-client.so.0.20.0" + "@PREFIX_LIB@/libwayland-client.so", + "@PREFIX_LIB@/libwayland-client.so.0", + "@PREFIX_LIB@/libwayland-client.so.0.20.0" ] }, "":{} diff --git a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h index 24b92f70c..463f5bea4 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h +++ b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h @@ -33,6 +33,10 @@ namespace FHU::Filesystem { return access(Path.c_str(), F_OK) == 0; } + inline bool ExistsAt(int FD, const fextl::string &Path) { + return faccessat(FD, Path.c_str(), F_OK, 0) == 0; + } + enum class CreateDirectoryResult { CREATED, EXISTS, diff --git a/Source/Tools/FEXLoader/LinuxSyscalls/FileManagement.cpp b/Source/Tools/FEXLoader/LinuxSyscalls/FileManagement.cpp index a6933f082..e67e22e20 100644 --- a/Source/Tools/FEXLoader/LinuxSyscalls/FileManagement.cpp +++ b/Source/Tools/FEXLoader/LinuxSyscalls/FileManagement.cpp @@ -15,6 +15,7 @@ $end_info$ #include "LinuxSyscalls/x64/Syscalls.h" #include +#include #include #include #include @@ -59,49 +60,62 @@ namespace JSON { } namespace FEX::HLE { - struct open_how; - -static bool LoadFile(fextl::vector &Data, const fextl::string &Filename) { - int fd = open(Filename.c_str(), O_RDONLY | O_CLOEXEC); - if (fd == -1) { - return false; - } - - struct stat buf; - if (fstat(fd, &buf) != 0) { - LogMan::Msg::DFmt("Couldn't load configuration file: fstat"); - close(fd); - return false; - } - - auto FileSize = buf.st_size; - - if (FileSize <= 0) { - LogMan::Msg::DFmt("FileSize less than or equal to zero specified"); - close(fd); - return false; - } - - Data.resize(FileSize); - const auto ReadSize = pread(fd, Data.data(), FileSize, 0); - - close(fd); - return ReadSize == FileSize; +bool FileManager::RootFSPathExists(const char* Filepath) { + LOGMAN_THROW_A_FMT(Filepath && Filepath[0] == '/', "Filepath needs to be absolute"); + return FHU::Filesystem::ExistsAt(RootFSFD, Filepath + 1); } -struct ThunkDBObject { - fextl::string LibraryName; - fextl::unordered_set Depends; - fextl::vector Overlays; - bool Enabled{}; -}; - -static void LoadThunkDatabase(fextl::unordered_map& ThunkDB, bool Is64BitMode, bool Global) { +void FileManager::LoadThunkDatabase(fextl::unordered_map& ThunkDB, bool Global) { auto ThunkDBPath = FEXCore::Config::GetConfigDirectory(Global) + "ThunksDB.json"; fextl::vector FileData; - if (LoadFile(FileData, ThunkDBPath)) { + if (FEXCore::FileLoading::LoadFile(FileData, ThunkDBPath)) { FileData.push_back(0); + // If the thunksDB file exists then we need to check if the rootfs supports multi-arch or not. + const bool RootFSIsMultiarch = RootFSPathExists("/usr/lib/x86_64-linux-gnu/") || + RootFSPathExists("/usr/lib/i386-linux-gnu/"); + + fextl::vector PathPrefixes{}; + if (RootFSIsMultiarch) { + // Multi-arch debian distros have a fairly complex arrangement of filepaths. + // These fractal out to the combination of library prefixes with arch suffixes. + constexpr static std::array LibPrefixes = { + "/usr/lib", + "/usr/local/lib", + "/lib", + "/usr/lib/pressure-vessel/overrides/lib", + }; + + // We only need to generate 32-bit or 64-bit depending on the operating mode. + const auto ArchPrefix = Is64BitMode() ? + "x86_64-linux-gnu" : + "i386-linux-gnu"; + + for (auto Prefix : LibPrefixes) { + PathPrefixes.emplace_back(fextl::fmt::format("{}/{}", Prefix, ArchPrefix)); + } + } + else { + // Non multi-arch supporting distros like Fedora and Debian have a much more simple layout. + // lib/ folders refer to 32-bit library folders. + // li64/ folders refer to 64-bit library folders. + constexpr static std::array LibPrefixes = { + "/usr", + "/usr/local", + "", // root, the '/' will be appended in the next step. + "/usr/lib/pressure-vessel/overrides", + }; + + // We only need to generate 32-bit or 64-bit depending on the operating mode. + const auto ArchPrefix = Is64BitMode() ? + "lib64" : + "lib"; + + for (auto Prefix : LibPrefixes) { + PathPrefixes.emplace_back(fextl::fmt::format("{}/{}", Prefix, ArchPrefix)); + } + } + JSON::JsonAllocator Pool { .PoolObject = { .init = JSON::PoolInit, @@ -143,39 +157,24 @@ static void LoadThunkDatabase(fextl::unordered_map } } else if (ItemName == "Overlay") { - auto AddWithReplacement = [Is64BitMode, HomeDirectory](ThunkDBObject& DBObject, fextl::string LibraryItem) { - constexpr static std::array LibPrefixes = { - "/usr/lib", - "/usr/local/lib", - "/lib", - "/usr/lib/pressure-vessel/overrides/lib", - }; - - constexpr static std::array ArchPrefixes = { - "i386", - "x86_64", - }; - + auto AddWithReplacement = [HomeDirectory, &PathPrefixes](ThunkDBObject& DBObject, fextl::string LibraryItem) { // Walk through template string and fill in prefixes from right to left using namespace std::string_view_literals; - const std::pair PrefixArch { "@PREFIX_ARCH@"sv, LibraryItem.find("@PREFIX_ARCH@") }; const std::pair PrefixHome { "@HOME@"sv, LibraryItem.find("@HOME@") }; const std::pair PrefixLib { "@PREFIX_LIB@"sv, LibraryItem.find("@PREFIX_LIB@") }; fextl::string::size_type PrefixPositions[] = { - PrefixArch.second, PrefixHome.second, PrefixLib.second, + PrefixHome.second, PrefixLib.second, }; // Sort offsets in descending order to enable safe in-place replacement std::sort(std::begin(PrefixPositions), std::end(PrefixPositions), std::greater<>{}); - for (auto& LibPrefix : LibPrefixes) { + for (auto& LibPrefix : PathPrefixes) { fextl::string Replacement = LibraryItem; for (auto PrefixPos : PrefixPositions) { if (PrefixPos == fextl::string::npos) { continue; - } else if (PrefixPos == PrefixArch.second) { - Replacement.replace(PrefixPos, PrefixArch.first.size(), ArchPrefixes[Is64BitMode]); } else if (PrefixPos == PrefixHome.second) { Replacement.replace(PrefixPos, PrefixHome.first.size(), HomeDirectory); } else if (PrefixPos == PrefixLib.second) { @@ -244,13 +243,20 @@ FileManager::FileManager(FEXCore::Context::Context *ctx) ConfigPaths.emplace_back(FEXCore::Config::GetApplicationConfig(AppName, false)); } + if (!LDPath().empty()) { + RootFSFD = open(LDPath().c_str(), O_DIRECTORY | O_PATH | O_CLOEXEC); + if (RootFSFD == -1) { + RootFSFD = AT_FDCWD; + } + } + fextl::unordered_map ThunkDB; - LoadThunkDatabase(ThunkDB, Is64BitMode(), true); - LoadThunkDatabase(ThunkDB, Is64BitMode(), false); + LoadThunkDatabase(ThunkDB, true); + LoadThunkDatabase(ThunkDB, false); for (const auto &Path : ConfigPaths) { fextl::vector FileData; - if (LoadFile(FileData, Path)) { + if (FEXCore::FileLoading::LoadFile(FileData, Path)) { JSON::JsonAllocator Pool { .PoolObject = { .init = JSON::PoolInit, @@ -339,13 +345,6 @@ FileManager::FileManager(FEXCore::Context::Context *ctx) } UpdatePID(::getpid()); - - if (!LDPath().empty()) { - RootFSFD = open(LDPath().c_str(), O_DIRECTORY | O_PATH | O_CLOEXEC); - if (RootFSFD == -1) { - RootFSFD = AT_FDCWD; - } - } } FileManager::~FileManager() { diff --git a/Source/Tools/FEXLoader/LinuxSyscalls/FileManagement.h b/Source/Tools/FEXLoader/LinuxSyscalls/FileManagement.h index 975e3f577..7a334388e 100644 --- a/Source/Tools/FEXLoader/LinuxSyscalls/FileManagement.h +++ b/Source/Tools/FEXLoader/LinuxSyscalls/FileManagement.h @@ -86,6 +86,15 @@ public: std::pair GetEmulatedFDPath(int dirfd, const char *pathname, bool FollowSymlink, FDPathTmpData &TmpFilename); private: + bool RootFSPathExists(const char* Filepath); + + struct ThunkDBObject { + fextl::string LibraryName; + fextl::unordered_set Depends; + fextl::vector Overlays; + bool Enabled{}; + }; + void LoadThunkDatabase(fextl::unordered_map& ThunkDB, bool Global); FEX::EmulatedFile::EmulatedFDManager EmuFD; fextl::map> ThunkOverlays;