Skip to content

Commit

Permalink
Merge pull request #2157 from Sonicadvance1/more_systemd_stuff
Browse files Browse the repository at this point in the history
FEXServer: More Systemd fixes
  • Loading branch information
Sonicadvance1 authored Nov 22, 2022
2 parents c7dd6ff + 10e35a5 commit 5e5e5a3
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 28 deletions.
69 changes: 51 additions & 18 deletions Source/Common/FEXServerClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,29 +100,55 @@ namespace FEXServerClient {
return GetServerLockFolder() + "RootFS.lock";
}

std::string GetServerSocketFile() {
FEX_CONFIG_OPT(ServerSocketPath, SERVERSOCKETPATH);
if (ServerSocketPath().empty()) {
auto TmpDir = std::filesystem::temp_directory_path().string();

auto XDGRuntimeEnv = getenv("XDG_RUNTIME_DIR");
if (XDGRuntimeEnv) {
// If the XDG runtime directory works then use that instead.
TmpDir = XDGRuntimeEnv;
}
std::string GetServerMountFolder() {
// We need a FEXServer mount directory that has some tricky requirements.
// - We don't want to use `/tmp/` if possible.
// - systemd services use `PrivateTmp` feature to gives services their own tmp.
// - We will use this as a fallback path /only/.
// - Can't be `[$XDG_DATA_HOME,$HOME]/.fex-emu/`
// - Might be mounted with a filesystem (sshfs) which can't handle mount points inside it.
//
// Directories it can be in:
// - $XDG_RUNTIME_DIR if set
// - Is typically `/run/user/<UID>/`
// - systemd `PrivateTmp` feature doesn't touch this.
// - If this path doesn't exist then fallback to `/tmp/` as a last resort.
// - pressure-vessel explicitly creates an internal XDG_RUNTIME_DIR inside its chroot.
// - This is okay since pressure-vessel rbinds the FEX rootfs from the host to `/run/pressure-vessel/interpreter-root`.
std::string Folder{};
auto XDGRuntimeEnv = getenv("XDG_RUNTIME_DIR");
if (XDGRuntimeEnv) {
// If the XDG runtime directory works then use that.
Folder = XDGRuntimeEnv;
}
else {
// Fallback to `/tmp/` if XDG_RUNTIME_DIR doesn't exist.
// Might not be ideal but we don't have much of a choice.
Folder = std::filesystem::temp_directory_path().string();
}

return fmt::format("{}/{}.FEXServer.socket", TmpDir, ::geteuid());
if (FEXCore::Config::FindContainer() == "pressure-vessel") {
// In pressure-vessel the mount point changes location.
// This is due to pressure-vesssel being a chroot environment.
// It by default maps the host-filesystem to `/run/host/` so we need to redirect.
// After pressure-vessel is fully set up it will set the `FEX_ROOTFS` environment variable,
// which the FEXInterpreter will pick up on.
Folder = "/run/host/" + Folder;
}

return ServerSocketPath;
return Folder;
}

std::string GetServerSocketName() {
return fmt::format("{}.FEXServer.Socket", ::geteuid());
}

int GetServerFD() {
return ServerFD;
}

int ConnectToServer() {
auto ServerSocketFile = GetServerSocketFile();
auto ServerSocketName = GetServerSocketName();

// Create the initial unix socket
int SocketFD = socket(AF_UNIX, SOCK_STREAM, 0);
Expand All @@ -131,12 +157,19 @@ namespace FEXServerClient {
return -1;
}

// AF_UNIX has a special feature for named socket paths.
// If the name of the socket begins with `\0` then it is an "abstract" socket address.
// The entirety of the name is used as a path to a socket that doesn't have any filesystem backing.
struct sockaddr_un addr{};
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, ServerSocketFile.data(), std::min(ServerSocketFile.size(), sizeof(addr.sun_path)));

if (connect(SocketFD, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) == -1) {
LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} {} {}", ServerSocketFile, errno, strerror(errno));
size_t SizeOfSocketString = std::min(ServerSocketName.size() + 1, sizeof(addr.sun_path) - 1);
addr.sun_path[0] = 0; // Abstract AF_UNIX sockets start with \0
strncpy(addr.sun_path + 1, ServerSocketName.data(), SizeOfSocketString);
// Include final null character.
size_t SizeOfAddr = sizeof(addr.sun_family) + SizeOfSocketString;

if (connect(SocketFD, reinterpret_cast<struct sockaddr*>(&addr), SizeOfAddr) == -1) {
LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} {} {}", ServerSocketName, errno, strerror(errno));
close(SocketFD);
return -1;
}
Expand Down Expand Up @@ -231,7 +264,7 @@ namespace FEXServerClient {

if (ServerFD == -1) {
// Still couldn't connect to the socket.
LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} after launching the process", GetServerSocketFile());
LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} after launching the process", GetServerSocketName());
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion Source/Common/FEXServerClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ namespace FEXServerClient {
std::string GetServerLockFolder();
std::string GetServerLockFile();
std::string GetServerRootFSLockFile();
std::string GetServerSocketFile();
std::string GetServerMountFolder();
std::string GetServerSocketName();
int GetServerFD();

bool SetupClient(char *InterpreterPath);
Expand Down
15 changes: 7 additions & 8 deletions Source/Tools/FEXServer/ProcessPipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,7 @@ namespace ProcessPipe {
}

bool InitializeServerSocket() {
auto ServerSocketFile = FEXServerClient::GetServerSocketFile();

// Unlink the socket file if it exists
// We are being asked to create a daemon, not error check
// We don't care if this failed or not
unlink(ServerSocketFile.c_str());
auto ServerSocketName = FEXServerClient::GetServerSocketName();

// Create the initial unix socket
ServerSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
Expand All @@ -195,10 +190,14 @@ namespace ProcessPipe {

struct sockaddr_un addr{};
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, ServerSocketFile.data(), std::min(ServerSocketFile.size(), sizeof(addr.sun_path)));
size_t SizeOfSocketString = std::min(ServerSocketName.size() + 1, sizeof(addr.sun_path) - 1);
addr.sun_path[0] = 0; // Abstract AF_UNIX sockets start with \0
strncpy(addr.sun_path + 1, ServerSocketName.data(), SizeOfSocketString);
// Include final null character.
size_t SizeOfAddr = sizeof(addr.sun_family) + SizeOfSocketString;

// Bind the socket to the path
int Result = bind(ServerSocketFD, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));
int Result = bind(ServerSocketFD, reinterpret_cast<struct sockaddr*>(&addr), SizeOfAddr);
if (Result == -1) {
LogMan::Msg::EFmt("Couldn't bind AF_UNIX socket '{}': {} {}\n", addr.sun_path, errno, strerror(errno));
close(ServerSocketFD);
Expand Down
2 changes: 1 addition & 1 deletion Source/Tools/FEXServer/SquashFS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ namespace SquashFS {

bool MountRootFSImagePath(std::string SquashFS, bool EroFS) {
pid_t ParentTID = ::getpid();
MountFolder = fmt::format("{}/.FEXMount{}-XXXXXX", std::filesystem::temp_directory_path().string(), ParentTID);
MountFolder = fmt::format("{}/.FEXMount{}-XXXXXX", FEXServerClient::GetServerMountFolder(), ParentTID);
char *MountFolderStr = MountFolder.data();

// Make the temporary mount folder
Expand Down

0 comments on commit 5e5e5a3

Please sign in to comment.