解决SteamOS系统更新造成软件包消失问题的方法

众所周知(也不一定),SteamOS是一个只读系统,并且使用了A/B分区(在Linux系统中挂载SteamOS的恢复镜像会发现有两个5G左右的分区,其内容是完全相同的)。这就导致了每一次SteamDeck更新系统后,我们通过sudo steamos-readonly disable 命令解开只读后,使用包管理器pacman所做的任何更改,都会被“抹去”。但是TMD抹不干净

因此,SteamOS更新后,使用包管理器pacman再次尝试下载软件包会报错,需要使用--overwrite 参数覆盖原先存在的目录,非常麻烦。

安装的软件消失也会导致一些奇奇怪怪的问题,比如说如果通过pacman的方式安装了proton-GE兼容层的话,更新系统后就无法使用了。

解决方案

先不提我是如何发现A/B分区以及哪些目录在更新后会被保留的。先说解决方案。

(果然,当我这种普通玩家发现这个问题的时候,真正的Geek已经开始解决问题了)

开源项目:Rwfus: Read-Write OverlayFS for your Steam Deck!

简介:Rwfus 覆盖了 Deck 的 /usr/ 目录(以及其他一些目录),允许您在 Steam Deck 上初始化和使用pacman(Arch Linux 软件包管理器)而不会在下一次更新发布时丢失软件包。

原理:

在会被保留的/home/.steamos/ 目录下建立一个目录,用于覆盖原先会被系统更新恢复初始化的目录。

挂载的目录如下:

Directory Contents
/etc/pacman.d pacman 设置
/usr 程序与依赖库
/var/cache/pacman 包缓存
/var/lib/pacman 元数据

安装方法

提示:由于最新版本SteamOS(当前为3.5.17)取消了usr-local.mount ,导致仓库的main分支安装后,systemd启动服务失败!需要切换分支!!!

提示:由于最新版本SteamOS(当前为3.5.17)取消了usr-local.mount ,导致仓库的main分支安装后,systemd启动服务失败!需要切换分支!!!

提示:由于最新版本SteamOS(当前为3.5.17)取消了usr-local.mount ,导致仓库的main分支安装后,systemd启动服务失败!需要切换分支!!!

好了,我们回到正题

安装方法:

  1. 克隆仓库到本地:git clone https://github.com/ValShaped/rwfus.git

  2. 切换到rwfus目录:cd rwfus

  3. 使用git命令切换分支为v0.5.0:git checkout v0.5.0

  4. 运行安装命令:./rwfus -iI

如果屏幕显示无报错,就说明安装正常了!

(deck@steamdeck rwfus)$ sudo ./rwfus -iI
Rwfus 0.5.0.b1 is only compatible with SteamOS 3.5
Are you sure you want to install Rwfus 0.5.0.b1? [y|N] y
Creating overlays for /usr /etc/pacman.d /var/cache/pacman:
1. Creating directories...
2. Generating disk image...
3. Generating service...
4. Storing configuration...
5. Copying service to /etc/systemd/system
6. Enabling service unit
7. Setting up pacman...
Done!

● rwfusd.service - Rwfus: Carry Pacman across SteamOS updates!
     Loaded: loaded (/etc/systemd/system/rwfusd.service; enabled; preset: disabled)
     Active: active (exited) since Wed 2024-03-06 19:47:36 CST; 22s ago
    Process: 17402 ExecStart=/opt/rwfus/service/rwfusd.sh --start (code=exited, status=0/SUCCESS)
   Main PID: 17402 (code=exited, status=0/SUCCESS)
        CPU: 167ms
Stopping Rwfus
Adding Rwfus to /home/.steamos/offload/usr/local/bin
Unmasking and enabling usr-local.mount
Restarting Rwfus
Done!

Log saved to /var/log/rwfus.log

此时pacman也可以正常使用了,并且不用担心更新系统会导致所作的更改不翼而飞了。

注意事项

由于 Valve 固件更新的工作方式,任何时候执行 pacman -S[y[y]]u 都会导致安装下一个固件更新时出现问题。

强烈建议在具有只读 rootfs 的 Steam Deck 上完全避免使用 -Su、-Syu 和 -Syyu。 它可能会导致不良后果。

Rwfus 现在仍在测试阶段(因此是 0.x 版本号,并且是用 Bash 编写的)。用它测试安装过几个用户包(nano-syntax-highlighting 和 yakuake)。

Rwfus还是一款正在开发中的软件,无法在使用过程中为Deck出现的任何问题负责。

Rwfus 允许您安装任何软件包,但并非所有软件包都能让您的 Deck 在更新后继续存在。特别是,glibc 会在更新后使您的 Deck 崩溃,需要 SteamOS 恢复映像以及一些 Linux 和 Rwfus 知识才能修复。

发现过程

(3月6日更新)

A/B分区

使用lsblk 命令检查SteamDeck的分区时,可以看到如下结果

(1)(deck@steamdeck ~)$ lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
nvme0n1     259:0    0  1.9T  0 disk
├─nvme0n1p1 259:1    0   64M  0 part
├─nvme0n1p2 259:2    0   32M  0 part
├─nvme0n1p3 259:3    0   32M  0 part
├─nvme0n1p4 259:4    0    5G  0 part /
├─nvme0n1p5 259:5    0    5G  0 part
├─nvme0n1p6 259:6    0  256M  0 part /var
├─nvme0n1p7 259:7    0  256M  0 part
└─nvme0n1p8 259:8    0  1.9T  0 part /var/tmp
                                     /var/log
                                     /var/lib/systemd/coredump
                                     /var/lib/steamos-log-submitter
                                     /var/lib/flatpak
                                     /var/lib/docker
                                     /srv
                                     /root
                                     /opt
                                     /nix
                                     /home

我们可以看到从p4分区,存在相同容量但是没有挂载点的一个分区。

解下来我们尝试挂载p5到/mnt,查看和p4的区别

(deck@steamdeck ~)$ sudo mount /dev/nvme0n1p5 /mnt
[sudo] password for deck:
(deck@steamdeck ~)$ ls /mnt
bin  boot  dev  efi  esp  etc  home  lib  lib64  mnt  nix  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
(deck@steamdeck ~)$ ls /
bin  boot  dev  efi  esp  etc  home  lib  lib64  mnt  nix  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

好吧,完全没有区别。因此确定SteamOS是使用A/B分区进行更新系统的。

应该也没人想看我交叉对比之中的文件吧(

可写入分区与游戏文件

根据分区表,可以发现nvme0n1p8下的文件似乎是和用户使用有关的,合理推测属于“系统更新后不会被扬的文件”

接下来,我们可以通过查找文件来佐证我们的猜想

首先查找运行游戏的兼容层

(deck@steamdeck ~)$ find -name *proton
./.local/share/Steam/steamapps/common/Proton - Experimental/proton
./.local/share/Steam/steamapps/common/Proton - Experimental/files/lib64/wine/vkd3d-proton
./.local/share/Steam/steamapps/common/Proton - Experimental/files/lib/wine/vkd3d-proton
./.local/share/Steam/steamapps/common/Proton 8.0/proton
./.local/share/Steam/steamapps/common/Proton 8.0/dist/lib64/wine/vkd3d-proton
./.local/share/Steam/steamapps/common/Proton 8.0/dist/lib/wine/vkd3d-proton

开始查找的目录为/home/deck,因此确信运行游戏的依赖存在于/home目录下,不受系统更新的影响。

查找游戏:

(deck@steamdeck ~)$ find -name *2077
./.local/share/Steam/userdata/0/1091500/ac/WinSavedGames/CD Projekt Red/Cyberpunk 2077
./.local/share/Steam/steamapps/compatdata/1091500/pfx/drive_c/users/steamuser/Documents/CD Projekt Red/Cyberpunk 2077
./.local/share/Steam/steamapps/compatdata/1091500/pfx/drive_c/users/steamuser/AppData/Local/Programs/CD Projekt Red/REDlauncher/gui/assets/videos/cp2077
./.local/share/Steam/steamapps/compatdata/1091500/pfx/drive_c/users/steamuser/AppData/Local/CD Projekt Red/Cyberpunk 2077
./.local/share/Steam/steamapps/compatdata/1091500/pfx/drive_c/users/steamuser/Saved Games/CD Projekt Red/Cyberpunk 2077
./.local/share/Steam/steamapps/common/Cyberpunk 2077

没毛病,一样的结果。

那么问题来了,/etc/目录作为Linux系统保留配置文件的目录,它的实际挂载点是哪呢?它会不会因为系统更新被扬了呢?

(3月7日更新)

经过查找,我发现/etc 目录为一个overlayfs(文件堆叠)系统。虽然目录是只读的,但是堆叠系统依旧可以将做出的更改保留下来。

(deck@steamdeck ~)$ mount | grep 'overlay'
overlay on /etc type overlay (rw,relatime,lowerdir=/new_root/etc,upperdir=/new_root/var/lib/overlays/etc/upper,workdir=/new_root/var/lib/overlays/etc/work)
overlay on /usr type overlay (rw,relatime,lowerdir=/usr,upperdir=/opt/rwfus/mount/upper/usr,workdir=/opt/rwfus/mount/work/usr,index=off,metacopy=off)
overlay on /etc/pacman.d type overlay (rw,relatime,lowerdir=/etc/pacman.d,upperdir=/opt/rwfus/mount/upper/etc-pacman.d,workdir=/opt/rwfus/mount/work/etc-pacman.d,index=off,xino=off,metacopy=off)

(deck@steamdeck ~)$ mount | grep '/etc'
overlay on /etc type overlay (rw,relatime,lowerdir=/new_root/etc,upperdir=/new_root/var/lib/overlays/etc/upper,workdir=/new_root/var/lib/overlays/etc/work)
overlay on /etc/pacman.d type overlay (rw,relatime,lowerdir=/etc/pacman.d,upperdir=/opt/rwfus/mount/upper/etc-pacman.d,workdir=/opt/rwfus/mount/work/etc-pacman.d,index=off,xino=off,metacopy=off)

这也就能解释为什么系统更新影响不到我们修改的一些配置了。

继续找找,这个“/new_root”具体是指什么东西

我们可以查找*.mount文件,看看具体执行了什么命令

(deck@steamdeck ~)$ ls /usr/lib/systemd/system/*.mount
 /usr/lib/systemd/system/dev-hugepages.mount   /usr/lib/systemd/system/proc-sys-fs-binfmt_misc.mount   /usr/lib/systemd/system/sys-kernel-tracing.mount   /usr/lib/systemd/system/var-lib-nfs-rpc_pipefs.mount
 /usr/lib/systemd/system/dev-mqueue.mount      /usr/lib/systemd/system/root.mount                      /usr/lib/systemd/system/tmp.mount                 '/usr/lib/systemd/system/var-lib-steamos\x2dlog\x2dsubmitter.mount'
 /usr/lib/systemd/system/etc.mount             /usr/lib/systemd/system/srv.mount                       /usr/lib/systemd/system/var-cache-pacman.mount     /usr/lib/systemd/system/var-lib-systemd-coredump.mount
 /usr/lib/systemd/system/nix.mount             /usr/lib/systemd/system/sys-fs-fuse-connections.mount   /usr/lib/systemd/system/var-lib-docker.mount       /usr/lib/systemd/system/var-log.mount
 /usr/lib/systemd/system/opt.mount             /usr/lib/systemd/system/sys-kernel-config.mount         /usr/lib/systemd/system/var-lib-flatpak.mount      /usr/lib/systemd/system/var-tmp.mount
 /usr/lib/systemd/system/proc-fs-nfsd.mount    /usr/lib/systemd/system/sys-kernel-debug.mount          /usr/lib/systemd/system/var-lib-machines.mount

(deck@steamdeck ~)$ cat /usr/lib/systemd/system/etc.mount
#  SPDX-License-Identifier: LGPL-2.1+
#
#  This file is part of steamos-customizations.
#
#  steamos-customizations is free software; you can redistribute it and/or
#  modify it under the terms of the GNU Lesser General Public License as
#  published by the Free Software Foundation; either version 2.1 of the License,
#  or (at your option) any later version.

[Unit]
Description=Etc Overlay

[Mount]
Where=/etc
What=overlay
Type=overlay
Options=lowerdir=/etc,upperdir=/var/lib/overlays/etc/upper,workdir=/var/lib/overlays/etc/work

[Install]
WantedBy=local-fs.target

好了,这下知道了

Options=lowerdir=/etc,upperdir=/var/lib/overlays/etc/upper,workdir=/var/lib/overlays/etc/work

(A)(root@steamdeck ~)# cd /var/lib/overlays/etc/upper
(A)(root@steamdeck upper)# ls
ca-certificates  fonts  group-   gshadow-  hosts.backup.1709724674  ld.so.cache   localtime    machine-id      opt    passwd       samba        security  ssh  systemd
conf.d           group  gshadow  hosts     iwd                      ld.so.conf.d  logrotate.d  NetworkManager  pam.d  resolv.conf  sddm.conf.d  shadow    ssl  tmpfiles.d

之前我们有做过改动的部分都在这儿了。

一个鸟人罢了