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

发布于 2024-09-01 08:44:24 字数 322 浏览 9 评论 0原文

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

我知道在关闭时,我的应用程序将收到一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

轻许诺言 2024-09-08 08:44:24

也许有点晚了。是的,您可以通过调用 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

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

Maybe a little bit late. Yes, you can determine if a SIGTERM is in a shutting down process by invoking the runlevel command. Example:

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

save it as, say, term.sh and run it. By executing killall term.sh, you should able to see and investigate the run-level file in your home directory. By executing any of the following:

sudo reboot
sudo halt -p
sudo shutdown -P

and compare the difference in the file. Then you should have the idea on how to do it.

瀞厅☆埖开 2024-09-08 08:44:24

无法确定 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 use rc.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 a SIGTERM if he/she does not want the app to exit.

无力看清 2024-09-08 08:44:24

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

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 ...

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

1 jobs listed.

... 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.

烟雨凡馨 2024-09-08 08:44:24

从手动关闭:

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

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

From man shutdown:

If the time argument is used, 5 minutes before the system goes down
the /etc/nologin file is created to ensure that further logins shall
not be allowed.

So you can test existence of /etc/nologin. It is not optimal, but probably best you can get.

圈圈圆圆圈圈 2024-09-08 08:44:24

我想我明白了。

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

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.

#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");
ゃ懵逼小萝莉 2024-09-08 08:44:24

让您的应用程序对某些 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.

微凉 2024-09-08 08:44:24

参见man systemctl,你可以像这样确定系统是否正在关闭:

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

这是在bash中,但你可以用C中的'system'来做到这一点

see man systemctl, you can determine if the system is shutting down like this:

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

this is in bash, but you can do it with 'system' in C

温馨耳语 2024-09-08 08:44:24

执行您最初想要的操作的实际答案是检查关闭过程(例如 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.

筑梦 2024-09-08 08:44:24

当系统关闭时,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.

策马西风 2024-09-08 08:44:24

请参阅手动关闭。请注意,要指定墙上消息,您还必须指定时间参数。如果使用时间参数,则在系统关闭前 5 分钟创建 /run/nologin 文件以确保不允许进一步登录。

示例Python:

if os.path.exists("/run/nologin"):
  print(now.strftime('Shutdown is pending yet %H:%M:%S on %A, %B the %dth, %Y'))
else:
  print(now.strftime('Waiting for shutdown-press at %H:%M:%S on %A, %B the %dth, %Y'))
  os.system("sudo shutdown -h +2 'Power will turn off in 2 min. Please Log Out.'")

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:

if os.path.exists("/run/nologin"):
  print(now.strftime('Shutdown is pending yet %H:%M:%S on %A, %B the %dth, %Y'))
else:
  print(now.strftime('Waiting for shutdown-press at %H:%M:%S on %A, %B the %dth, %Y'))
  os.system("sudo shutdown -h +2 'Power will turn off in 2 min. Please Log Out.'")
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文