Skip to content

Steamのゲームを外部ディスクにインストールできない

Flatpakは /run/media/ 以下にマウントされた外部ディスクを暗黙的に認識する。このディスクはFlatpakコンテナ内で /run/user/xxx/doc に出現する。

問題は、このディスクにあるファイルを flock しているところで errno = 38 が出ている。このエラーコードは ENOSYS で、定義によると Function not implemented だった。以下はログの一部。

flock /run/user/60331/doc/f9ec6bc3/Steam/libraryfolder.vdf LOCK_SH failed. errno = 38
flock /run/user/60331/doc/f9ec6bc3/Steam/steamapps/appmanifest_1384160.acf LOCK_SH failed. errno = 38
flock /run/user/60331/doc/f9ec6bc3/Steam/steamapps/appmanifest_1892700.acf LOCK_SH failed. errno = 38
flock /run/user/60331/doc/f9ec6bc3/Steam/steamapps/appmanifest_239120.acf LOCK_SH failed. errno = 38
flock /run/user/60331/doc/f9ec6bc3/Steam/libraryfolder.vdf LOCK_SH failed. errno = 38

Flatpakのパーミッションはおそらく read, write, grant-permissions, delete くらいしかないので、少なくとも読み書きするために必要なものは設定されている。

Terminal window
$ flatpak permissions
Table Object App Permissions Data
gnome shortcuts-inhibitor qemu.desktop DENIED []
background background com.valvesoftware.Steam yes 0x00
documents f9ec6bc3 com.valvesoftware.Steam read,write,grant-permissions (b'/run/media/lufia/games/Steam', 76, 257, 4)

類似の事例も報告されていた。

xdg-document-portal がFUSEとして本物のデバイスへのアクセスを中継しているが、これが flock を実装していないことが原因。

Steamを起動してマウント状態をみたところ、/run/user/60331 には tmpfs がマウントされている。

Terminal window
$ grep /run/user /proc/$(pidof -s steam)/mounts
tmpfs /run/user/60331 tmpfs rw,nosuid,nodev,relatime,size=3255252k,nr_inodes=813813,mode=700,uid=60331,gid=60331,inode64 0 0

上のログでは flock でエラーが発生していたので、Flatpakコンテナ内で確認したところ同様のエラーになった。

Terminal window
$ flatpak run --command=bash com.valvesoftware.Steam
[📦 com.valvesoftware.Steam ~]$ cd /run/user/60331/doc/f9ec6bc3/Steam/
[📦 com.valvesoftware.Steam Steam]$ ls
libraryfolder.vdf steamapps
[📦 com.valvesoftware.Steam Steam]$ flock -s libraryfolder.vdf ls
flock: libraryfolder.vdf: Function not implemented

当然だがホスト側から /run/media/ を触った場合は flock も動作する。

Sandbox Permissionsによると、以下の場所にはアクセスが許されている。

  • the runtime
  • the app
  • ~/.var/app/$FLATPAK_ID
  • $XDG_RUNTIME_DIR/app/$FLATPAK_ID

Steamの場合、最後の場所は /run/user/(user)/app/com.valvesoftware.Steam/ のこと。なので /run/user/60331/doc/f9ec6bc3/Steam は許可されていない可能性はある。Sandbox Permissionsxdg-run/path に権限を与えれば /app 以外でも参照できるらしい。

ホストとコンテナで挙動が異なる理由

Section titled “ホストとコンテナで挙動が異なる理由”

同じファイルシステムにアクセスしているのに、ホスト上で実行した時は問題なく、Flatpakコンテナ内だとエラーになる挙動の違いはどこに原因があるのか。直接マウントしているなら同じように動くはずなので、 /proc/mounts に出現しているこれが怪しい。

portal /run/flatpak/doc fuse.portal rw,nosuid,nodev,relatime,user_id=60331,group_id=60331 0 0

portal デバイスの fuse.portal タイプとは何かというと、FlatpakがXDG Desktop Portal由来のディレクトリをマウントするためのものらしい。これはSandbox Permissions/Portalsによれば、サンドボックスを実現するための一部として実装されている。そうしてPortalはフロントエンドとバックエンドに分かれていて、バックエンドはそれぞれのデスクトップ環境ごとに存在する。

最初のログでエラーが発生していた /run/user/60331/doc はシンボリックリンクになっていて、参照先は /run/flatpak/doc を指していた。そういうことなら、 flock でロックが取れないのはXDG Desktop Portalのフロントエンドが実装していないからだろう。ここまで分かったので ValveSoftware/steam-for-linux リポジトリにイシューを作った。

現状のソースコードでFUSEのオペレーションを定義しているのは document-portal-fuse.cxdp_fuse_oper 変数libfuse には高レベルAPIと低レベルAPIの2種類があるけれど、2024年頃の xdg-document-portal は低レベルAPIの fuse_lowlevel_ops 構造体で実装していた。

static struct fuse_lowlevel_ops xdp_fuse_oper = {
.init = xdp_fuse_init_cb,
.destroy = xdp_fuse_destroy_cb,
.lookup = xdp_fuse_lookup,
...
.setlk = xdp_fuse_setlk,
.flock = xdp_fuse_flock,
.fallocate = xdp_fuse_fallocate,
};

ここで flock メンバーにxdp_fuse_flock が設定されているけど、実装をみるとエラーを返しているだけだった。

static void
xdp_fuse_flock (fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info *fi,
int lock_op)
{
const char *op = "FLOCK";
g_debug ("FLOCK %lx", ino);
xdp_reply_err (op, req, ENOSYS);
}

meson を使う。 doc/contributing.rst に書かれているように実行する。

Terminal window
sudo pacman -S meson pkgconf
meson setup . _build
meson compile -C _build
meson install # 必要なら
# cleanが必要なら
ninja -C _build clean

systemdのユニットが /usr/lib/systemd/user/xdg-document-portal.service にあって、それは単に /usr/lib/xdg-document-portal を実行しているだけだった。

[Unit]
Description=flatpak document portal service
PartOf=graphical-session.target
[Service]
Type=dbus
BusName=org.freedesktop.portal.Documents
ExecStart=/usr/lib/xdg-document-portal
Slice=session.slice

ということは一時的にこれを、手元でビルドしたコマンドに置き換えて試せばいい。

Terminal window
umount /run/user/60331/doc
./xdg-document-portal &

原因は分かったが、flock をポータルに実装するにあたっては困難な課題があるので諦めた。詳細は以下のリンク先に書いてある。