对于术语、语法、约定等的任何损坏,提前表示歉意。我仍然是一个相当新手的 Linux 用户。我正在开发运行最新 SteamOS (3.5.17) 的 Steam Deck。
我成功地使用设置了启动和关闭服务系统它可以在 Steam Deck 和我在 Raspberry Pi 上设置的 SAMBA 共享网络驱动器之间同步游戏保存。我将驱动器设置为在“/home/deck/mnt/xtra/”处自动安装(通过 fstab)。每个服务运行巴什启动和关闭时分别调用“sync_saves.sh”的脚本。
问题是我还想将脚本“sync_saves.sh”存储在网络驱动器上并从那里运行它,以便我可以更轻松地更新它。该脚本读取从不同计算机频繁更新的配置文件(也在网络上)。我不希望他们每个人都有自己的本地版本,因为手动保持它们同步变得非常痛苦。但是,虽然我可以直接从网络驱动器运行脚本,服务如果脚本位于网络驱动器上,则不会运行。如果有任何错误,我在运行时不会看到它们:
systemctl --user status ss_lin_startup
这两个服务在名为 ss_lin_startup.service 和 ss_lin_shutdown.service 的文件中定义。以下是他们的内容:
ss_lin_startup.service
[Unit]
Description=SyncSaves Startup
[Service]
#ExecStart=/home/deck/mnt/xtra/scripts/SyncSaves/sync_saves.sh #network drive, doesn't work
ExecStart=/home/deck/Documents/scripts/SyncSaves/sync_saves.sh #local drive, works
[Install]
WantedBy=default.target
ss_lin_shutdown.service
[Unit]
Description=SyncSaves Shutdown
[Service]
Type=oneshot
RemainAfterExit=true
#ExecStop=/home/deck/mnt/xtra/scripts/SyncSaves/sync_saves.sh #network drive, doesn't work
ExecStop=/home/deck/Documents/scripts/SyncSaves/sync_saves.sh #local drive, works
[Install]
WantedBy=default.target
我通过将服务文件的链接放在“/home/deck/.config/systemd/user/”中并运行以下命令来让它们工作(当脚本存储在本地驱动器上时):
systemctl --user daemon-reload
systemctl --user enable ss_lin_startup.service
systemctl --user enable ss_lin_shutdown.service
如果重要的话,服务文件存储在“/home/deck/Documents/scripts/SyncSaves/services”中,链接在文件夹“/home/deck/.config/systemd/user/”中。 Steam Deck 桌面环境提供了以移动、复制或链接方式拖放文件的选项,这是我用来创建链接的方法。
有办法让它发挥作用吗?我以正确的方式处理这件事吗?或者,有没有办法让我在启动时自动将脚本“sync_saves.sh”从网络驱动器复制到本地驱动器?
我已经谷歌搜索了几个小时,我得到的唯一提示如下:
-我在某处看到 systemd 不喜欢服务位于不同的分区(大概来自系统分区),但我不确定我是否理解正确,或者含义是否适用于此,或者脚本所在的位置是否重要调用被存储。
- 在有关此主题的大多数讨论中,服务都放置或链接在“/etc/systemd/system/”中,启用它们的命令是“systemctl enable your_service.service”,不带 --user 标志,有时使用 sudo 。在我对 Raspberry Pi 的初步测试中,我使用了这种方法,但在 Steam Deck 上遇到了问题。
更新:
我解决了问题的一部分,但仍然没有解决方案。我怀疑可能会发生这种情况,但不知道如何补救。我跑了
systemctl --user -l status ss_lin_startup.service
并得到更多细节输出。它显示“无法找到可执行文件...sync_saves.sh”。因此,可能发生的情况(至少在启动时)是驱动器尚未安装。我见过人们在服务文件中使用不同的参数来确保命令在网络启动后运行(即 Wants=network-online.target、After=network-online.target),但是当我使用这些参数时,我得到类似“未找到目标”。
最终更新:
我想出了一个解决办法,即编写一个更新脚本(从网络驱动器中提取最新版本的sync_saves.sh和配置文件),然后编写一个脚本来运行更新脚本,然后运行同步脚本。这样它就按预期工作了。我不确定这里可以取得多少进展,因为似乎没有很多关于 SteamOS 特性的信息。
答案1
- 如果 SELINUX 处于执行默认模式(例如在 RHEL 8.9 中)selinux 将阻止服务运行,除非该
/home/deck/mnt/xtra/scripts/SyncSaves/sync_saves.sh
文件标有允许其运行的 selinux 上下文。我问过这个问题,似乎没有任何硬性约定,所以除非你想编写自己的 selinux 规则,否则我只是将其标记为bin_t
.- 自定义 systemd 服务的 ExecStart 的 selinux 上下文
semanage fcontext -a -t bin_t "/home/deck/mnt/xtra/scripts/SyncSaves/sync_saves.sh"
restorecon -vR /home/deck/mnt/xtra/scripts/SyncSaves/sync_saves.sh
- 对于 SELINUX 其他选项是
- 通过在提示符处执行操作将其实时设置为宽容模式
setenforce 0
,然后进行故障排除,如果问题立即消失,如果是这样,则说明是 selinux 阻止了它 - 您可以通过执行 a 来观察 selinux 阻塞的情况
tail -f /var/log/audit/audit.log
,并在发生时观察打印输出 /etc/selinux/config
通过编辑然后重新启动将selinux全局设置为宽容模式;建议不要将其设置为禁用,除非您知道自己在做什么,因为这可能会导致问题; permissive 基本上被禁用==允许一切,但也会打印audit.log中可能出现问题的内容。
- 通过在提示符处执行操作将其实时设置为宽容模式
systemd 服务不会从网络驱动器运行
因为如果按照如下方式/home/deck/Documents/scripts/SyncSaves/sync_saves.sh
安装该安装,则脚本或任何脚本或任何与此相关的文件将不会执行。执行 a并查看 a 是否作为安装选项存在。还要确保从文件中调用的文件对于将运行该文件的用户具有执行权限。noexec
/etc/fstab
sync_saves.sh
mount | grep home
noexec
.sh
.service
我在某个地方看到 systemd 不喜欢服务位于不同的分区上。
这服务systemctl list-unit-files
是在执行daemon-reload
.... 您的文件后识别的文件ss_lin_startup.service
。无论该服务文件通过execstart
或execstop
其他方式调用,任何被调用执行的文件都必须具有每个 selinux 规则的 selinux 标签,当 selinux 强制执行时,该标签将被允许运行,而该bin_t
标签就是其中之一。该文件的位置并不重要,除非它位于具有noexec
挂载选项的 nfs 挂载下。
还要确保您的第一行sync_saves.sh
有 a #!/bin/bash
,如果不是,我的经验是从文件调用时它不会运行.service
。
答案2
对于问题的主要部分,即如何从网络文件系统运行 systemd 服务,基本上有两个问题。一种是向 systemd 单元添加一个条件,告诉它需要给定的路径/挂载点可用。另一个是 systemd 首先如何实际挂载该路径/挂载点,因为您需要依赖它。
- systemd 单元对路径的依赖
您应该尝试通过以下方式添加对网络文件系统路径的依赖关系需要安装=选项。这也适用于分层安装(/home 可能是一个单独的文件系统,而 /home/deck/mnt/xtra 是根据您的解释安装在其下方的网络文件系统)
引用描述:
采用空格分隔的绝对路径列表。自动为访问指定路径所需的所有安装单元添加 Requires= 和 After= 类型的依赖项。
标有 noauto 的挂载点不会通过 local-fs.target 自动挂载,但仍会出于此选项的目的而受到尊重,即它们将被该单元拉入。
所以尝试添加
RequiresMountsFor=/home/deck/mnt/xtra/scripts/SyncSaves/sync_saves.sh
给你的ss_lin_startup.service
.您可以通过运行来轻松地做到这一点systemctl edit --full --user ss_lin_startup.service
,这将让您编辑您的 systemd 服务,并且它也应该在之后执行systemctl daemon-reload --user
。
- systemd 如何从 /etc/fstab 挂载条目
/etc/fstab 中的所有条目均由 systemd 通过解析systemd-fstab-生成器.mount
它会在每次启动时为它们中的每个创建所谓的单元。对于网络文件系统,您应该始终添加_netdev作为 /etc/fstab 条目的一个选项,因为它被解析,从而systemd-fstab-generator
添加了对remote-fs.target
.这通常足够可靠,可以让 systemd 在挂载网络文件系统之前等待网络可用。
--- * 通常意味着网络启动和网络在线之间存在区别,即启动的网络连接之一实际上能够到达任何内容。尽管这本身就是一个非常复杂的主题,并且可能超出了本问题/答案的范围。