如何在使用 systemd 关闭时在其他所有内容之前运行脚本?

le_*_*_me 21 linux shutdown administrator systemd

注意:可以在底部找到简要制定的问题。

我有一个脚本可以将我的文件备份到外部 USB 驱动器上。执行它可能需要一段时间,具体取决于我创建的新数据量。我想在系统每次关闭时自动运行它。

我正在使用带有最新更新 (systemd) 的 Fedora 23。

我试图通过多种方式实现这一目标,但我无法让它发挥作用。

使用 StopExec 长时间运行的进程

自动备份服务:

[Unit]
Description=Slow backup script
Requires=local-fs.target

[Service]
ExecStart=/bin/true
ExecStop=/etc/systemd/system/do_backup.sh
Type=oneshot
RemainAfterExit=yes

[Install]
WantedBy=multiuser.target
Run Code Online (Sandbox Code Playgroud)

我用 激活它systemctl enable autobackup.service并用 启动它systemctl start autobackup.service

我的启动日志 ( journalctl -b-1) 的一部分:

Dez 22 17:45:27 localhost systemd[1]: Unmounted /mnt/BACKUP.
Dez 22 17:45:27 localhost do_backup.sh[4296]: At subvol /home/BACKUP.2015_12_22-17_45_25
Dez 22 17:45:27 localhost do_backup.sh[4296]: ERROR: parent subvol is not reachable from inside the root subvol.
Dez 22 17:45:27 localhost do_backup.sh[4296]: At snapshot BACKUP.2015_12_22-17_45_25
Dez 22 17:45:27 localhost do_backup.sh[4296]: ERROR: failed to dump stream. Broken pipe
Dez 22 17:45:27 localhost systemd[1]: autobackup.service: Control process exited, code=exited status=1
Dez 22 17:45:27 localhost systemd[1]: Stopped Slow backup script.
Dez 22 17:45:27 localhost systemd[1]: autobackup.service: Unit entered failed state.
Run Code Online (Sandbox Code Playgroud)

请注意,我没有缩短中间的任何内容,它确实在脚本开始之前卸载了 /mnt/BACKUP,有趣的巧合..

关机前.target

自动备份服务:

[Unit]
Description=Slow backup script
DefaultDependencies=no
Before=shutdown.target

[Service]
ExecStart=/etc/systemd/system/do_backup.sh
Type=oneshot
Run Code Online (Sandbox Code Playgroud)

systemctl edit shutdown.target

[Unit]
Requires=autobackup.service
Run Code Online (Sandbox Code Playgroud)

输出基本相同。

问题

我认为问题在于 systemd 在这两种情况下都与所有其他关闭脚本并行启动我的脚本,这会卸载 BACKUP 并停用管道基础设施(当卸载速度不够快时,我有时会遇到另一个错误)。

问题

我怎样才能教 systemd 在关机时首先启动我的脚本,等到它退出,然后再启动其余的关机脚本/目标/单元/什么的?

小智 13

无需创建或编辑服务文件。只需将您的脚本放入

/usr/lib/systemd/system-shutdown/
Run Code Online (Sandbox Code Playgroud)

https://www.freedesktop.org/software/systemd/man/systemd-halt.service.html

在执行实际系统halt/poweroff/reboot/kexec systemd-shutdown 之前,将运行/usr/lib/systemd/system-shutdown/ 中的所有可执行文件,并向它们传递一个参数:“halt”、“poweroff”、“rebo​​ot” " 或 "kexec",取决于选择的操作。此目录中的所有可执行文件都是并行执行的,并且在所有可执行文件完成之前不会继续执行操作。

我用它来简单地使 PC 扬声器发出哔哔声。

  • OP 要求在关机时“在其他一切之前”执行脚本。系统关闭脚本在执行其他所有操作之后,即在杀死内核之前立即执行。 (15认同)
  • Debian 系统使用不同的路径 `/lib/systemd/system-shutdown/`。另外请注意,这些脚本在关闭时很晚才执行,在文件系统已经以只读方式挂载之后。所以任何对文件系统的写访问都将失败,除非重新挂载为读写(`mount -oremount,rw /`)。请参阅[如何在 /usr/lib/systemd/system-shutdown/ 重启或关机时执行脚本?](http://unix.stackexchange.com/q/347306/159562) (3认同)
  • 你必须制作这个目录吗?我在 Ubuntu 16.04 和 Raspbian (jessie) 上都没有它——两者都是基于 systemd 的。 (2认同)

le_*_*_me 12

我知道了!

使用 StopExec解决长期运行的进程并像这样修改它:

自动备份服务:

[Unit]
Description=Slow backup script
RequiresMountsFor=/mnt/BACKUP /home

[Service]
ExecStop=/etc/systemd/system/do_backup.sh
Type=oneshot
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
Run Code Online (Sandbox Code Playgroud)

注意这一行:

RequiresMountsFor=/mnt/BACKUP /home
Run Code Online (Sandbox Code Playgroud)

它以这种方式按预期工作。

  • 这对我不起作用。我没有任何坐骑,我只想确保我的脚本在其他设备关闭之前运行。 (4认同)
  • 你不应该需要做`systemctl edit`。`systemctl enable autobackup` 具有相同的效果并且更符合习惯,并且应该可以工作,因为您的单元中已经有了 `[Install]` 部分。但是,您必须更正目标名称中的拼写错误。;) (2认同)