如何检测在Linux上挂起的系统关机?

我正在一个应用程序,我需要检测系统closures。 但是,我还没有find任何可靠的方式得到这个事件的通知。

我知道在关机时,我的应用程序将收到一个SIGTERM信号,接着是一个SIGKILL 。 我想知道是否有任何方法来查询SIGTERM是否是closures序列的一部分

有没有人知道是否有方法来查询编程(C API)?

据我所知,系统不提供任何其他方法来查询即将closures。 如果是的话,那也能解决我的问题。 我一直在尝试runlevels ,但runlevels变化似乎是瞬间的,没有任何预先警告。

Solutions Collecting From Web of "如何检测在Linux上挂起的系统关机?"

也许有点晚了 是的,您可以通过调用runlevel命令来确定SIGTERM是否处于关闭进程中。 例:

 #!/bin/bash trap "runlevel >$HOME/run-level; exit 1" term read line echo "Input: $line" 

将其保存为term.sh并运行。 通过执行killall term.sh ,您应该能够查看并调查主目录中的run-level文件。 通过执行以下任一操作:

 sudo reboot sudo halt -p sudo shutdown -P 

并比较文件中的差异。 那么你应该知道如何去做。

从人关机:

如果使用time参数,则在系统关闭前5分钟创建/etc/nologin文件,以确保不允许进一步的登录。

所以你可以测试/etc/nologin存在。 这不是最佳的,但可能是最好的,你可以得到。

无法确定SIGTERM是否是关闭序列的一部分。 要检测关闭序列,您可以使用像ereOn和Eric Sepanson建议的rc.d脚本,或者使用像DBus这样的机制。

但是,从设计角度来看,即使不是关机的一部分,忽略SIGTERM也是没有意义的。 SIGTERM的主要目的是礼貌地要求应用程序完全退出,如果某人拥有足够的特权,如果他/她不希望该应用程序退出,则不太可能发出SIGTERM

使您的应用程序对某些SIGTERM信号的反应不同于其他SIGTRM信号似乎是不透明的,可能会造成混淆 有争议的是,你应该总是以同样的方式回应给定的信号。 添加不寻常的条件使得难以理解和测试应用程序的行为。

添加一个处理关闭的rc脚本(通过发送一个特殊的信号)是一个完全标准的方法来处理这样的问题。 如果这个脚本是作为标准软件包( make install或rpm / deb软件包)的一部分安装的,那么不应该担心控制用户机器。

它有一点点黑客,但如果服务器运行systemd,如果你可以运行

/bin/systemctl list-jobs shutdown.target

它会报告…

 JOB UNIT TYPE STATE 755 shutdown.target start waiting <---- existence means shutting down 1 jobs listed. 

…如果服务器正在关闭或重新启动(提示:有一个reboot.target,如果你想专门看)

您将得到No jobs running. 如果没有关机。

你必须解析输出有点麻烦,因为systemctl不会返回两个结果的不同退出码。 但它确实似乎相当可靠。 但是,如果更新系统,则需要注意消息中的格式更改。

我想我明白了。

来源= https://github.com/mozilla-b2g/busybox/blob/master/miscutils/runlevel.c

我在这里复制部分代码,以防引用消失。

 #include "libbb.h" ... struct utmp *ut; char prev; if (argv[1]) utmpname(argv[1]); setutent(); while ((ut = getutent()) != NULL) { if (ut->ut_type == RUN_LVL) { prev = ut->ut_pid / 256; if (prev == 0) prev = 'N'; printf("Runlevel: prev=%c current=%c\n", prev, ut->ut_pid % 256); endutent(); return 0; } } puts("unknown"); 

当系统关闭时,调用rc.d脚本。

也许你可以添加一个脚本,发送一些特殊的信号给你的程序。

但是,我怀疑你可以通过这种方式停止系统关机。

做你最初想要的实际答案是你检查关机过程(例如ps aux | grep“shutdown -h”),然后,如果你想确定你检查它的命令行参数和它开始的时间(例如14:51开始的“shutdown -h +240”将在18:51关闭)。

在一般情况下, 从整个系统的角度来看,没有办法做到这一点。 “关机”有很多种不同的方式。 例如,某人可以决定拔掉插头,以便在停机时刻硬停止一个程序,使他们现在具有不良/危险的行为,或者UPS可能首先发送一个SIGHUP,然后简单地失败。 由于这样的关闭可能会突然发生,并且系统中没有任何警告,因此无法确定在SIGHUP之后继续运行是否可行。

如果一个进程收到SIGHUP,你应该基本上认为一些很快就会出现的东西。 如果你想做一些特殊的事情并且部分地忽略SIGHUP,那么a)你需要与任何程序进行协调,并且b)你需要做好准备,如果其他系统在SIGHUP之后立即关闭并杀死你你的软件和数据将会存活。 写出你所拥有的任何数据,只要继续写入安全原子更新的附加文件即可。

对于您的情况,我几乎可以确定您当前的解决方案(将所有SIGHUP视为关机)是正确的方法。 如果你想改进的东西,你可能应该添加一个功能,通过DBUS或类似的东西通知关闭程序。

man systemctl ,你可以确定系统是否正在关闭如下:

 if [ "`systemctl is-system-running`" = "stopping" ]; then # Do what you need fi 

这是在bash中,但你可以用C中的'system'来完成