2009-01-20 74 views
4

假設長時間運行的進程寫入日誌文件。假設日誌文件無限期地保持打開狀態。假設一個粗心的系統管理員刪除該日誌文件。程序是否可以檢測到發生了這種情況?在POSIX系統上檢測到該日誌文件已被刪除或截斷?

是否安全地假設fstat()將報告已刪除文件的鏈接計數爲零?

截斷,在我看來,有點棘手。部分取決於文件描述符是否在O_APPEND模式下運行。如果日誌文件未與O_APPEND一起運行,那麼程序日誌描述符的當前寫入位置不會改變,並且截斷將刪除前導字節,但程序將繼續在「結束」處寫入,從而留下幻影間隙零字節(它們讀爲零,但不一定佔用磁盤空間)。

如果程序以O_APPEND運行,那麼它將在文件末尾寫入當前存在的文件末尾。觀察截斷的唯一方法是注意文件位置不在程序期望的位置 - 這又意味着明確跟蹤該位置。

整體而言,我並不擔心截斷與刪除一樣,但任何想法都會受到歡迎。

+0

如何鎖定而不是檢測刪除? – 2009-01-20 17:02:08

+0

@snot:我不明白這會有多大幫助。諮詢鎖定將被忽略;強制鎖定是不尋常的 - 不是不可能的,但我不想。另外,應允許管理員在合理範圍內操作日誌。這可能是軟件需要更好的「更改日誌文件」機制。 – 2009-01-20 17:59:56

+0

文件名只是指向文件的指針,當沒有指向文件時它將被刪除。既然你總是可以添加一個鏈接然後刪除另一個鏈接計數可能沒有幫助,你可以做的最好的辦法是檢查文件名是否仍然存在,或者如果你的過程是唯一一個鏈接到文件。 – 2009-01-20 18:28:07

回答

3

檢查fstat()返回鏈接計數爲零將失敗,如果文件被硬鏈接或重命名。我可能會定期比較stat()的inode編號與fstat()的編號。

我不確定截斷。

tail -F檢查刪除和可能截斷,所以我會檢查它的來源,看看它是如何實現它。

1

你可以使用inotify來觀察你的日誌文件,監視它的文件系統事件。

2

假設不小心的系統管理員殺死進程。你真的想防止管理員做隨機的事情嗎?我想你只是在尋找一種不時啓動新日誌文件的方式,例如使用logrotate。在那裏提供一種手動讓程序重新打開日誌文件的方法就足夠了。這樣做的標準方法是偵聽HUP信號的程序,並重新打開日誌文件,如果它到達:

#include <signal.h> 

volatile int f_sighup; 

void sighup_handler() { 
    f_sighup = 1; 
} 

void trap_sighup() { 
    struct sigaction sa; 
    int rv; 

    memset(&sa, 0, sizeof(struct sigaction)); 
    sa.sa_handler = &sighup_handler; 
    rv = sigaction(SIGHUP, &sa, NULL); 
    if (-1 == rv) { 
    fprintf(stderr, "warning: setting SIGHUP signal handler failed"); 
    } 
} 

int main() { 
    f_sighup = 0; 
    trap_sighup(); 
    ... 
} 

然後定期檢查f_sighup標誌主程序,看看日誌文件應該是重新開放。 這很適合像logrotate這樣的工具,它可以重命名舊的日誌文件,然後調用kill -s HUP $PID。粗心的系統管理員可以在刪除(或更好地重命名)舊的日誌文件之後手動執行此操作。

-1

當一個文件關閉時,修改時間被改變。因此,使用stat()定期檢查mtime是否可行。

1

響應於søren-holmanswer

當文件被關閉的修改時間被改變。

不似乎是正確的:

import os 
from time import sleep 

TMPF = '/tmp/f' 

def print_stats(): 
    print("%s, %s" % (os.stat(TMPF).st_mtime, os.stat(TMPF).st_ctime)) 
    sleep(1.1) 

print("Opening...") 
with open(TMPF, 'w') as f: 
    print_stats() 
    print("Writing...") 
    os.write(f.fileno(), 'apple') 
    print_stats() 
    print("Flushing...") 
    f.flush() 
    print_stats() 
    print("Closing...") 

print_stats() 

產地:

Opening... 
1483052647.08, 1483052647.08 
Writing... 
1483052648.18, 1483052648.18 
Flushing... 
1483052648.18, 1483052648.18 
Closing... 
1483052648.18, 1483052648.18 

誠然,有一些Python魔術在那裏往前走; write()不能合理保證自動刷新,但是這個觀點表明mtime在文件被修改時更新,而不是在文件關閉時更新。 ctime的行爲將取決於您的文件系統及其掛載選項。