2010-05-14 37 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與「系統」做