#include "ConfigDefines.h" #include "Common/Config.h" #include "Common/FileFormatCheck.h" #include #include #include #include #include #include #include #include namespace FEX::RootFS { bool Setup(char **const envp) { // We need to setup the rootfs here // If the configuration is set to use a folder then there is nothing to do // If it is setup to use a squashfs then we need to do something more complex FEX_CONFIG_OPT(LDPath, ROOTFS); if (FEX::FormatCheck::IsSquashFS(LDPath())) { pid_t ParentTID = ::getpid(); std::string ParentTIDString = std::to_string(ParentTID); std::string Tmp = "/tmp/.FEXMount" + ParentTIDString + "-XXXXXX"; char *TempFolder = Tmp.data(); // Make the temporary mount folder if (mkdtemp(TempFolder) == nullptr) { LogMan::Msg::E("Couldn't create temporary mount name: %s", TempFolder); return false; } // Change the permissions if (chmod(TempFolder, 0777) != 0) { LogMan::Msg::E("Couldn't change permissions on temporary mount: %s", TempFolder); rmdir(TempFolder); return false; } // Open some pipes for communicating with the new processes int fds[2]{}; if (pipe2(fds, 0) != 0) { LogMan::Msg::E("Couldn't open pipe"); return false; } // Convert the write pipe to a string to pass to the child process std::string PipeString; PipeString = std::to_string(fds[1]); pid_t pid = fork(); if (pid == 0) { // Child close(fds[0]); // Close read end of pipe const char *argv[6]; argv[0] = FEX_INSTALL_PREFIX "/bin/FEXMountDaemon"; argv[1] = LDPath().c_str(); argv[2] = TempFolder; argv[3] = ParentTIDString.c_str(); argv[4] = PipeString.c_str(); argv[5] = nullptr; if (execve(argv[0], (char * const*)argv, envp) == -1) { // Let the parent know that we couldn't execute for some reason uint64_t error{1}; write(fds[1], &error, sizeof(error)); // Give a hopefully helpful error message for users LogMan::Msg::E("Couldn't execute: %s", argv[0]); LogMan::Msg::E("This means the squashFS rootfs won't be mounted."); LogMan::Msg::E("Expect errors!"); // Destroy this fork exit(1); } } else { // Parent // Wait for the child to exit so we can check if it is mounted or not close(fds[1]); // Close write end of the pipe // Wait for a message from FEXMountDaemon pollfd PollFD; PollFD.fd = fds[0]; PollFD.events = POLLIN; poll(&PollFD, 1, -1); // Read a value from the pipe to get an expected result // This will come from FEXMountDaemon or our local fork depending on results uint64_t ChildResult{}; int Result = read(fds[0], &ChildResult, sizeof(ChildResult)); if (Result != sizeof(ChildResult)) { LogMan::Msg::D("Spurious read error"); return false; } if (ChildResult == 1) { // Error LogMan::Msg::D("FEXMountDaemon couldn't mount child for some reason"); return false; } // Check if we have an directory inside our temp folder std::string Path = TempFolder; std::string PathUser = Path + "/usr"; if (!std::filesystem::exists(PathUser)) { LogMan::Msg::D("Child couldn't mount rootfs, /usr doesn't exist"); rmdir(TempFolder); return false; } // If everything has passed then we can now update the rootfs path FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_ROOTFS, Path); return true; } } // Nothing to do return true; } }