Skip to content

Refactor creation of symlinks in an emulator's interpreter root

Simon McVittie requested to merge wip/task342-2 into main

steamrt/tasks#342. Follow-up for !600 (merged).

As usual, best reviewed commit-by-commit.


  • !627 (merged)

  • pv-wrap: Mount graphics provider in $FEX_ROOTFS/var under FEX-Emu

    We have to mount the graphics provider below $FEX_ROOTFS, so that when other parts of the $FEX_ROOTFS have symbolic links into it, those symlinks are resolved successfully even with FEX's interference (it resolves symlinks as if chrooted into the $FEX_ROOTFS).

    However, if we mount anything below $FEX_ROOTFS/run, that has the undesired effect that sockets mounted in the real root filesystem's /run are not visible to a readdir() by emulated x86 code. If we move the graphics provider outside /run, we can avoid this.

  • pv-wrap: Mount interpreter's real root on /run/interpreter-root

    This makes room for /run/host to be used for the $FEX_ROOTFS. We currently implement this by distinguishing between /run/host and $FEX_ROOTFS/run/host, but we want to stop doing that, because it interferes with path resolution for /run if it exists inside the $FEX_ROOTFS.

  • pv-wrap: Don't distinguish between /run/host and $FEX_ROOTFS/run/host

    As with previous commits, if we do that, then sockets mounted in the real /run won't show up in a readdir() by x86 code.

  • pv-runtime: Move MUTABLE_LDSO_DIR from /run to /var

    Inside our container, both /run and /var are on tmpfs, so both are equally suitable. Using /var for this has the advantage that it avoids a split-brain situation where ARM and x86 code under FEX-Emu will see different content in /run.

    /var is already split between the real root used by ARM code and the $FEX_ROOTFS used by x86 code.

  • pv-runtime: Ensure we don't create symlinks in $FEX_ROOTFS/run, etc.

    No functional change: all of the current callers are creating symlinks in /etc or /var, or creating the /overrides symlink. This will matter more when we expand the use of this function, to check that we're still using it correctly.

  • pv-wrap: Don't convert pv_wrap_share_sockets() paths to interpreter root

    Most of what we export via FlatpakExports or pv_wrap_share_sockets either is meant to show up at a corresponding path inside the container's real root, for example /home -> /home, or belongs to /var and is meant to show up at a corresponding path in the real root and/or the $FEX_ROOTFS, for example /var/tmp -> /var/tmp.

    However, some paths that come via pv_wrap_share_sockets() are bind-mounts with their destination inside /run/host, for example $FEX_ROOTFS/usr/share/fonts -> /run/host/fonts. We want to mount those in the real root, not in the $FEX_ROOTFS, to avoid a split-brain situation where ARM and x86 code sees a different /run.

  • pv-runtime: Ensure /run/pressure-vessel/pv-from-host is resolvable

    Now that our $FEX_ROOTFS does not have its own /run, we need this to point to a path that physically exists.

  • pv-runtime: Add infrastructure to make symlinks in real + emulated roots

    This will allow commit 5e0f8520 "pv-runtime: Duplicate symlinks in /etc, /var in the interpreter root" to be generalized to cover more of the symlinks we create.

    No functional change intended, yet: all callers currently pass in EMULATION_ROOTS_INTERPRETER_ONLY, which has the same behaviour that MAKE_SYMLINK_FLAGS_INTERPRETER_ROOT previously did.

    EMULATION_ROOTS_REAL_ONLY replaces the (currently unused) MAKE_SYMLINK_FLAGS_NONE, and EMULATION_ROOTS_BOTH is new and does both at the same time.

  • tests: Unit-test pv_runtime_make_symlink_in_container()

  • pv-runtime: Add a function to set up a --ro-bind

    This will allow each --ro-bind to be classified into real root, interpreter root, or both when using FEX-Emu.

  • tests: Unit-test pv_runtime_bind_into_container()

  • pv-runtime: Mount /etc, /var from runtime into interpreter root if appropriate

    This generalizes commit 5e0f8520 "pv-runtime: Duplicate symlinks in /etc, /var in the interpreter root" to use shared machinery. For symlinks, no functional change is intended; for regular files and directories, this commit gives them the same handling.

    This ensures that readdir() on those paths by an x86 process in FEX-Emu will show all the files: previously, they would not show up in readdir() (but, confusingly, directly opening them would still have worked).

    This function call cannot legitimately fail, because the only reason for it to fail would be if the destination was outside /var, which it is not; so treat failure as a programming error, which will cause a critical warning.

    steamrt/tasks#342

  • pv-runtime: Create machine ID in interpreter root, too

    As with previous commits, this ensures that a readdir() on /etc or /var/lib by an x86 process under FEX-Emu will show it as existing.

    This also reduces repetition a little.

    This is actually slightly nicer than what happens under FEX-Emu without using pressure-vessel, which is that the machine ID only exists in the real root and does not show up in readdir().

  • pv-runtime: Create /etc/localtime, /etc/timezone in interpreter root

    As with previous commits, this means they'll show up in a readdir() from /etc by an x86 process under FEX-Emu.

    This is actually slightly nicer than what happens under FEX-Emu without using pressure-vessel, which is that these files only exist in the real root and do not show up in readdir().

  • pv-runtime: Provide /etc/asound.conf inside and outside interpreter root

    This ensures that it shows up in a readdir() of /etc.

    As with previous commits, this is actually slightly nicer than what happens under FEX-Emu without using pressure-vessel, which is that the file only exists in the real root and does not show up in readdir().

  • pv-runtime: Bind-mount /etc/passwd, etc. into interpreter root too

    As with previous commits, this ensures that they show up in a readdir() of /etc by an x86 process under FEX-Emu. This commit covers files that we get from the host system.

    As with previous commits, this is actually slightly nicer than what happens under FEX-Emu without using pressure-vessel, which is that these files only exist in the real root and do not show up in readdir() (except for host.conf, which arguably shouldn't be in the rootfs either).

  • pv-runtime: Use pv_runtime_bind_into_container for files from provider

    For files in /etc (and in theory /var), no functional change is intended: this just converts an open-coded equivalent of pv_runtime_bind_into_container() into a call into common code.

    However, for sockets in /run (as of this commit, only /run/bumblebee.socket, but others might be added in future), we only want to populate the real root's /run, not the rootfs' /run; so we need to distinguish between those two cases.

  • pv-runtime: Refactor creating emulator ld.so setup

    This just puts them through common code, and converts repeated similar function calls to be table-driven. No functional change intended: they continue to be written to the interpreter root only, as before.

  • pv-runtime: Comment where handling of interpreter root is not needed

    No functional changes in this commit, other than repeating the assertion that mutable_sysroot == NULL implies absence of PV_RUNTIME_FLAGS_INTERPRETER_ROOT in functions that didn't already have it.

Edited by Simon McVittie

Merge request reports