假设长时间运行的进程写入日志文件。假设日志文件无限期保持打开状态。假设粗心的系统管理员删除该日志文件。程序可以检测到这种情况发生了吗?
假设fstat()
报告已删除文件的链接数为零是否安全?
O_APPEND
模式运行。如果日志文件没有运行O_APPEND
,那么程序日志描述符的当前写入位置不会改变,截断将删除前导字节,但程序继续写入“结束”,离开幻象零字节的间隙(它们读为零,但不一定占用磁盘上的空间)。
如果程序以O_APPEND
运行,则它将在文件末尾写入,因为它当前存在。观察截断的唯一方法是注意文件位置不是程序所期望的位置 - 这反过来意味着明确地跟踪该位置。
总的来说,我并不担心截断会被删除,但任何想法都会受到欢迎。
答案 0 :(得分:4)
如果文件被硬链接或重命名,则检查fstat()
返回链接计数为零将失败。我可能会定期将stat()
的inode编号与fstat()
进行比较。
我不确定截断。
tail -F
检查删除和截断,所以我会检查它的来源,看看它是如何实现的。
答案 1 :(得分: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
。在删除(或更好地重命名)旧日志文件之后,粗心的sysadmin可以手动执行此操作。
答案 2 :(得分:1)
您可以使用inotify来查看日志文件,并针对文件系统事件进行监控。
答案 3 :(得分:1)
回复https://s24.postimg.org/45fed3pth/Screen_Shot_2016_12_30_at_10_08_01_am.png&#39; søren-holm
关闭文件时,修改时间会更改。
看起来不正确:
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
的行为将取决于您的文件系统及其挂载选项。
答案 4 :(得分:-1)
关闭文件时,修改时间会更改。因此,使用stat()定期检查mtime会有效。