2010-05-14 71 views
14

我正在研究一个需要检测系统关闭的应用程序。 但是,我还没有找到任何可靠的方式获得有关此事件的通知。如何检测Linux上挂起的系统关机?

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

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

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

+0

有趣的问题。你想停止关机还是仅仅收到通知? – ereOn 2010-05-14 07:17:26

+0

我只是想通知。 – 341008 2010-05-14 08:07:51

+0

我已经放弃了。我已决定将任何SIGTERM视为OS要关闭的消息。我的(蹩脚的)理由是,SIGTERM的主要目的是礼貌地要求应用程序完全退出,并且如果具有足够特权的人不希望应用程序退出,则发出SIGTERM不太可能。即使它不是关机应用程序应该听取它。这给我带来了另一个问题。关机序列中SIGTERM和SIGKILL之间的最短时间是多少?我知道它可以使用-t开关配置,但是有最小限制吗? – 341008 2010-05-19 10:56:15

回答

5

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

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

1

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

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

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

+0

感谢您的快速回答。我无法控制我的应用程序将部署在机器上,所以我无法更改它们上的任何内容。另外,我不想停止关机。我只想知道什么时候关机即将发生。 – 341008 2010-05-14 08:07:19

+0

我恐怕没有什么别的事情可做了(至少,我能想到)。也许如果你向我们解释你想达到的目标,我们可能会帮助你找到另一种选择? – ereOn 2010-05-14 13:54:59

3

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

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

5

从人关机:

如果使用的时间参数,系统出现故障 创建/etc/nologin文件,以确保进一步的登录应 不允许前5分钟。

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

+0

嗯..我不知道你是否可以使用'inotifywait'来响应它的创建... – Izkata 2014-01-29 14:54:43

10

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

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

保存为,比方说,term.sh并运行它。通过执行killall term.sh,你应该能够看到和调查run-level文件在你的home目录。通过执行以下任一操作:

sudo reboot 
sudo halt -p 
sudo shutdown -P 

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

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犯规了两个结果返回不同的退出代码。但它似乎确实合理可靠。但是,如果更新系统,则需要注意消息中的格式更改。

+0

这似乎不适用于我 – 2016-09-23 21:44:41

+0

谢谢,对我有用 – Javi 2017-05-17 18:43:19

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"); 
0

实际回答你最初想要的是你检查关机处理(例如,PS辅助| grep的“执行shutdown -h”),然后,如果你要确保你检查它的命令行参数和开始时间(例如,“关机-h + 240”在14:51开始将在18:51关闭)。

在一般情况下有从整个系统的角度来看没有办法做到这一点。 “关机”可能会发生很多不同的方式。例如有人能决定拉以硬插停止程序,他们现在已经在关机时或UPS坏/危险行为可能首先发送一个SIGHUP,然后简单地失败。由于这种关闭可能突然没有警告发生在一个系统中任何地方也没有办法,以确保它的好保持SIGHUP后运行。

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

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

1

看到man systemctl,可以判断系统是否关闭这样的:

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

这是在bash,但你可以在C与“系统”做