如何检测 Linux 上挂起的系统关闭?
我正在开发一个需要检测系统关闭的应用程序。 但是,我还没有找到任何可靠的方法来获取有关此事件的通知。
我知道在关闭时,我的应用程序将收到一个 SIGTERM
信号,然后是一个 SIGKILL
。我想知道是否有任何方法可以查询 SIGTERM
是否是关闭序列的一部分?
有谁知道是否有一种方法可以以编程方式查询(C API)?
据我所知,系统没有提供任何其他方法来查询即将关闭。如果是的话,那也能解决我的问题。我也一直在尝试运行级别,但是运行级别的更改似乎是瞬时的,并且没有任何事先警告。
I am working on an application where I need to detect a system shutdown.
However, I have not found any reliable way get a notification on this event.
I know that on shutdown, my app will receive a SIGTERM
signal followed by a SIGKILL
. I want to know if there is any way to query if a SIGTERM
is part of a shutdown sequence?
Does any one know if there is a way to query that programmatically (C API)?
As far as I know, the system does not provide any other method to query for an impending shutdown. If it does, that would solve my problem as well. I have been trying out runlevels
as well, but change in runlevels
seem to be instantaneous and without any prior warnings.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
也许有点晚了。是的,您可以通过调用 runlevel 命令来确定 SIGTERM 是否处于关闭过程中。示例:
将其保存为
term.sh
并运行它。通过执行killall term.sh
,您应该能够查看并调查主目录中的run-level
文件。通过执行以下任一操作:并比较文件中的差异。然后你应该知道如何去做。
Maybe a little bit late. Yes, you can determine if a SIGTERM is in a shutting down process by invoking the runlevel command. Example:
save it as, say,
term.sh
and run it. By executingkillall term.sh
, you should able to see and investigate therun-level
file in your home directory. By executing any of the following:and compare the difference in the file. Then you should have the idea on how to do it.
无法确定
SIGTERM
是否是关闭序列的一部分。要检测关闭序列,您可以使用 rc.d 脚本(如 ereOn 和 Eric Sepanson 建议的脚本)或使用 DBus 等机制。然而,从设计的角度来看,忽略
SIGTERM
是没有意义的,即使它不是关闭的一部分。SIGTERM
的主要目的是礼貌地要求应用程序完全退出,并且拥有足够权限的人不太可能发出SIGTERM
如果他/她不希望应用程序退出。There is no way to determine if a
SIGTERM
is a part of a shutdown sequence. To detect a shutdown sequence you can either use userc.d
scripts like ereOn and Eric Sepanson suggested or use mechanisms like DBus.However, from a design point of view it makes no sense to ignore
SIGTERM
even if it is not part of a shutdown.SIGTERM
's primary purpose is to politely ask apps to exit cleanly and it is not likely that someone with enough privileges will issue aSIGTERM
if he/she does not want the app to exit.它有点像黑客,但如果服务器正在运行 systemd 如果你可以运行
/bin/systemctl list-jobs shutdown.target
...它会报告 ...
...如果服务器正在关闭或重新启动(提示:如果您想专门查找的话,有一个reboot.target)
如果没有关闭,您将得到
No jobs running.
。您必须解析有点混乱的输出,因为 systemctl 不会为两个结果返回不同的退出代码。但它看起来确实相当可靠。但是,如果您更新系统,则需要注意消息中的格式更改。
Its a little bit of a hack but if the server is running systemd if you can run
/bin/systemctl list-jobs shutdown.target
... it will report ...
... if the server is shutting down or rebooting ( hint: there's a reboot.target if you want to look specifically for that )
You will get
No jobs running.
if its not being shutdown.You have to parse the output which is a bit messy as the systemctl doesnt return a different exit code for the two results. But it does seem reasonably reliable. You will need to watch out for a format change in the messages if you update the system however.
从手动关闭:
所以你可以测试
/etc/nologin
是否存在。它不是最佳的,但可能是您能得到的最好的。From man shutdown:
So you can test existence of
/etc/nologin
. It is not optimal, but probably best you can get.我想我明白了。
来源=
https://github.com/mozilla-b2g/busybox/blob /master/miscutils/runlevel.c
我在这里复制了部分代码,以防引用消失。
I think I got it.
Source =
https://github.com/mozilla-b2g/busybox/blob/master/miscutils/runlevel.c
I copy part of the code here, just in case the reference disappears.
让您的应用程序对某些 SIGTERM 信号的响应与其他信号不同似乎是不透明的并且可能会造成混乱。有争议的是,您应该始终以相同的方式响应给定的信号。添加异常条件会使理解和测试应用程序行为变得更加困难。
添加处理关闭的 rc 脚本(通过发送特殊信号)是处理此类问题的完全标准方法;如果此脚本作为标准包(
make install
或 rpm/deb 打包)的一部分安装,则无需担心用户计算机的控制。Making your application responding differently to some SIGTERM signals than others seems opaque and potentially confusing. It's arguable that you should always respond the same way to a given signal. Adding unusual conditions makes it harder to understand and test application behavior.
Adding an rc script that handles shutdown (by sending a special signal) is a completely standard way to handle such a problem; if this script is installed as part of a standard package (
make install
or rpm/deb packaging) there should be no worries about control of user machines.参见
man systemctl
,你可以像这样确定系统是否正在关闭:这是在bash中,但你可以用C中的'system'来做到这一点
see
man systemctl
, you can determine if the system is shutting down like this:this is in bash, but you can do it with 'system' in C
执行您最初想要的操作的实际答案是检查关闭过程(例如 ps aux | grep "shutdown -h" ),然后,如果您想确保检查它的命令行参数和启动时间(例如,“shutdown -h +240”于 14:51 启动,将于 18:51 关闭)。
在一般情况下,从整个系统的角度来看没有办法做到这一点。发生“关闭”的方式有很多种。例如,某人可能决定拔掉插头以硬停止一个程序,因为他们现在在关机时有不良/危险行为,或者 UPS 可能首先发送 SIGHUP,然后简单地失败。由于这种关闭可能会突然发生,并且系统中任何地方都不会发出警告,因此无法确定在 SIGHUP 后是否可以继续运行。
如果一个进程收到 SIGHUP,您基本上应该假设很快就会发生更糟糕的事情。如果你想做一些特殊的事情并部分忽略 SIGHUP 那么 a)你需要与任何将执行关闭操作的程序进行协调 b)你需要做好准备,如果其他系统执行关闭操作并在 SIGHUP 后很快杀死你您的软件和数据将继续存在。写出您拥有的所有数据,并且仅继续写入具有安全原子更新的仅附加文件。
对于您的情况,我几乎可以肯定您当前的解决方案(将所有 SIGHUP 视为关闭)是正确的方法。如果您想改进,您可能应该向关闭程序添加一项功能,该功能通过 进行通知DBUS 或类似的东西。
The practical answer to do what you originally wanted is that you check for the shutdown process (e.g ps aux | grep "shutdown -h" ) and then, if you want to be sure you check it's command line arguments and time it was started (e.g. "shutdown -h +240" started at 14:51 will shutdown at 18:51).
In the general case there is from the point of view of the entire system there is no way to do this. There are many different ways a "shutdown" can happen. For example someone can decide to pull the plug in order to hard stop a program that they now has bad/dangerous behaviour at shutdown time or a UPS could first send a SIGHUP and then simply fail. Since such a shutdown can happen suddenly and with no warning anywhere in a system there is no way to be sure that it's okay to keep running after a SIGHUP.
If a process receives SIGHUP you should basically assume that something nastier will follow soon. If you want to do something special and partially ignore SIGHUP then a) you need to coordinate that with whatever program will do the shutdown and b) you need to be ready that if some other system does the shutdown and kills you dead soon after a SIGHUP your software and data will survive. Write out any data you have and only continue writing to append-only files with safe atomic updates.
For your case I'm almost sure your current solution (treat all SIGHUPs as a shutdown) is the correct way to go. If you want to improve things, you should probably add a feature to the shutdown program which does a notify via DBUS or something similar.
当系统关闭时,
rc.d
脚本将被调用。也许您可以在那里添加一个脚本,向您的程序发送一些特殊信号。
但是,我怀疑您是否可以通过这种方式停止系统关闭。
When the system shuts down, the
rc.d
scripts are called.Maybe you can add a script there that sends some special signal to your program.
However, I doubt you can stop the system shutdown that way.
请参阅
手动关闭
。请注意,要指定墙上消息,您还必须指定时间参数。如果使用时间参数,则在系统关闭前 5 分钟创建/run/nologin
文件以确保不允许进一步登录。示例Python:
See
man shutdown
. Note that to specify a wall message you must specify a time argument, too. If the time argument is used, 5 minutes before the system goes down the/run/nologin
file is created to ensure that further logins shall not be allowed.Example Python: