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

时间:2010-05-14 07:00:49

标签: c linux sigterm system-shutdown

我正在开发一个需要检测系统关闭的应用程序。 但是,我没有找到任何可靠的方式来获取此事件的通知。

我知道在关机时,我的应用会收到一个SIGTERM信号,然后是SIGKILL。我想知道是否有任何方法可以查询SIGTERM关闭序列的一部分

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

据我所知,系统没有提供任何其他方法来查询即将发生的关机。如果是这样,那也可以解决我的问题。我一直在尝试runlevels,但runlevels的更改似乎是即时的,没有任何预先警告。

9 个答案:

答案 0 :(得分:11)

也许有点晚了。是的,您可以通过调用运行级别命令来确定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

并比较文件中的差异。然后你应该知道如何做到这一点。

答案 1 :(得分:6)

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

但是,从设计的角度来看,忽略SIGTERM是没有意义的,即使它不是关闭的一部分。 SIGTERM的主要目的是礼貌地要求应用程序彻底退出,并且如果他/她不想要,则具有足够权限的人不太可能发出SIGTERM应用退出。

答案 2 :(得分:5)

从男人关机:

  

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

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

答案 3 :(得分:3)

使您的应用程序对某些SIGTERM信号的响应与其他信号不同似乎不透明且可能令人困惑。有争议的是,您应该始终以相同的方式响应给定的信号。添加异常条件会使理解和测试应用程序行为变得更加困难。

添加处理关闭的rc脚本(通过发送特殊信号)是处理此类问题的完全标准方法;如果此脚本作为标准软件包(make install或rpm / deb打包)的一部分安装,则不必担心控制用户计算机。

答案 4 :(得分:2)

它有点像黑客,但如果服务器正在运行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没有为两个结果返回不同的退出代码。但它似乎相当可靠。但是,如果更新系统,则需要注意消息中的格式更改。

答案 5 :(得分:2)

我想我明白了。

来源= 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");

答案 6 :(得分:2)

请参阅man systemctl,您可以确定系统是否正在关闭:

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

这是bash,但你可以用C

中的'system'来做

答案 7 :(得分:1)

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

也许您可以在那里添加一个脚本,向您的程序发送一些特殊信号。

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

答案 8 :(得分:1)

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

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

如果一个进程收到SIGHUP,你基本上应该假设很快就会有更糟糕的东西。如果你想做一些特别的事情并部分忽略SIGHUP那么a)你需要协调它与任何程序将关闭和b)你需要准备,如果其他系统关闭并在SIGHUP后很快杀死你您的软件和数据将继续存在。写出您拥有的任何数据,并继续写入具有安全原子更新的仅附加文件。

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