我有一个在 RHEL7 上运行并由 systemd 启动的 Linux 进程。 当进程停止时,我需要知道它是否由于系统关闭或重新启动而停止,并且我需要能够区分这两者。
以前,在 RHEL6 上的 init 下,我可以通过查看用于调用 init 脚本的路径名来执行此操作,并相应地向进程发送不同的信号,即:
case "$0" in
*rc0\.d*|*rc1\.d*) #shutdown
sig=USR1
;;
*rc6\.d*) #reboot
sig=USR2
;;
*)
sig=TERM
;;
esac
这不适用于 systemd...尽管我的 init 脚本在正确的时间被调用,但 $0 始终是相同的(/etc/init.d/scriptname)。
systemd 下是否有某种方法可以知道您是否因系统关闭或重新启动而被呼叫? 我很高兴摆脱 init 脚本并将其配置为 systemd 目标,但从文档中我看不到一种方法来执行我想要的操作。
CameronNemo 的评论是正确的。特殊的 systemd 目标在
man systemd.special
或 http://linuxmanpages.net/manpages/fedora14/man7/systemd.special.7.html 中进行了描述,并且重新启动目标在重新启动时处于活动状态。然而,关闭目标在任何形式的系统终止时都是活动的,无论是重新引导还是停止,因此它无助于区分。对于其他感兴趣的目标,请参阅man telinit
。我已经成功使用以下类型的代码:
/usr/bin/systemctl list-jobs | egrep -q 'shutdown.target.*start' && echo "shutting down" || echo "not shutting down"
/usr/bin/systemctl list-jobs | egrep -q 'reboot.target.*start' && echo "-> rebooting" || echo "-> not rebooting"
/usr/bin/systemctl list-jobs | egrep -q 'halt.target.*start' && echo "-> halting" || echo "-> not halting"
/usr/bin/systemctl list-jobs | egrep -q 'poweroff.target.*start' && echo "-> powering down" || echo "-> not powering down"
关闭系统时,它总是会显示“正在关闭”,然后根据重新启动或关闭电源,还会显示“正在重新启动”或“正在关闭电源”。
/sbin/halt
将导致“停止”。当我尝试时,shutdown -h now
会转换为关闭电源,但这可能取决于虚拟环境与物理环境。我已使用 Fedora 20 (ami-21362b48) 和 CentOS7 (ami-96a818fe) 在 EC2 us-east 中进行了测试。如果您遇到这不起作用的情况,请发表评论,我会尽力修复!
感谢@TvE 的初步研究和出色的回答,从而产生了这个简化/增强版本。
我想(迂腐地)改进(我确信仍然100%足够)
systemctl
在TvE的答案中提出的解析,然后我发现运行时不支持输出JSONsystemctl list-jobs
。
所以我深入兔子洞,比较了
systemctl list-units --ty=target --al --o=json
、poweroff
、shutdown now
和 halt
期间 reboot
的输出,并了解到了这一点;
事实证明,当系统出现故障时(由于
poweroff
、shutdown now
、halt
或 reboot
),大多数 loaded 目标将是相同的,并且它们都将包含 shutdown.target
;相关差异是:
poweroff
和 shutdown now
将加载完全相同的目标;halt
,与 poweroff
/ shutdown now
相比,将缺少 poweroff.target
,但将包含 halt.target
;reboot
,与 poweroff
/ shutdown now
相比,将缺少 poweroff.target
,但将包含 reboot.target
;因此,不仅可以通过查看 loaded 单元来区分它们,而且为了确定系统是否正在重新启动,只需检查
reboot.target
是否为 loaded:
systemctl list-units --ty=target --al --o=json |
jq -e 'any(.[]; .unit=="reboot.target")' >/dev/null
# system is rebooting, will return exit status 0
systemctl list-units --ty=target --al --o=json |
jq -e 'any(.[]; .unit=="reboot.target") | not' >/dev/null
# system is not rebooting, will return exit status 1