分类: LINUX
2015-04-28 13:47:00
从文件管理器到安全工具,文件系统监控对于的许多程序来说都是必不可少的。从 Linux 2.6.13 内核开始,Linux 就推出了 inotify,允许监控程序打开一个独立文件描述符,并针对事件集监控一个或者多个文件,例如打开、关闭、移动/重命名、删除、创建或者改变属性。在后期的内核中有了很多增强,因此在依赖这些特性之前,请先检查您的内核版本。
inotify提供接口主要有3个:
inotify_init() - 创建一个inotify实例
inotify_add_watch(int fd, const char *pathname, uint32_t mask) - 加入文件或目录到inotify进行监测
inotify_rm_watch(int fd, int wd) - 移除一个watcher
struct inotify_event { int wd; /* Watch descriptor. */ uint32_t mask; /* Watch mask. */ uint32_t cookie; /* Cookie to synchronize two events. */ uint32_t len; /* Length (including NULs) of name. */ char name __flexarr; /* Name. */ };
请注意,只有当监控对象是一个目录并且事件与目录内部相关项目有关,而与目录本身无关时,才提供 name 字段。
如果 IN_MOVED_FROM 事件与相应的 IN_MOVED_TO 事件都与被监控的项目有关,cookie 就可用于将两者关联起来。
事件类型在掩码字段中返回,并伴随着能够被内核设置的标志。例如,如果事件与目录有关,则标志 IN_ISDIR 将由内核设置。
适用于 inotify_add_watch mask 与 read 返回的inotify_event中mask
IN_ACCESS
文件被访问
IN_ATTRIB
文件属性发生变化
IN_CLOSE_WRITE
以write方式打开文件并关闭
IN_CLOSE_NOWRITE
以非write方式打开文件并关闭
IN_CREATE
文件或目录被创建
IN_DELETE
文件或目录被删除(被监测的文件夹A中B文件被删除)
IN_DELETE_SELF
被监测的文件或目录被删除(被监测的文件夹A被删除)
IN_MODIFY
文件被修改
IN_MOVE_SELF
被监测的文件或目录移动
IN_MOVED_FROM
文件移出被监测的目录
IN_MOVED_TO
文件移入被监测的目录
IN_OPEN
文件被打开
上述flag的集合
IN_ALL_EVENTS
以上所有flag的集合
IN_MOVE
IN_MOVED_TO|IN_MOVED_FROM
IN_CLOSE
IN_CLOSE_WRITE|IN_CLOSE_NOWRITE
不常用的flag
IN_DONT_FOLLOW
不follow符号链接 (since 2.6.15)
IN_EXCL_UNLINK
当文件从监测目中unlink后,则不再报告该文件的相关event,比如监控/tmp使用 (since 2.6.36)
IN_MASK_ADD
追打MASK到被监测的pathname
IN_ONESHOT
只监测一次
IN_ONLYDIR
只监测目录
仅由read返回
IN_IGNORED
inotify_rm_watch,文件被删除或者文件系统被umount
IN_ISDIR
发生事件的是一个目录
IN_Q_OVERFLOW
Event队列溢出
IN_UNMOUNT
文件系统unmount
#include
#include
#include
#include
#include
struct EventMask {
int flag;
const char *name;
};
struct EventMask event_masks[] = {
{IN_ACCESS , "IN_ACCESS"},
{IN_ATTRIB , "IN_ATTRIB"},
{IN_CLOSE_WRITE , "IN_CLOSE_WRITE"},
{IN_CLOSE_NOWRITE , "IN_CLOSE_NOWRITE"},
{IN_CREATE , "IN_CREATE"},
{IN_DELETE , "IN_DELETE"},
{IN_DELETE_SELF , "IN_DELETE_SELF"},
{IN_MODIFY , "IN_MODIFY"},
{IN_MOVE_SELF , "IN_MOVE_SELF"},
{IN_MOVED_FROM , "IN_MOVED_FROM"},
{IN_MOVED_TO , "IN_MOVED_TO"},
{IN_OPEN , "IN_OPEN"},
{IN_DONT_FOLLOW , "IN_DONT_FOLLOW"},
// {IN_EXCL_UNLINK , "IN_EXCL_UNLINK"},
{IN_MASK_ADD , "IN_MASK_ADD"},
{IN_ONESHOT , "IN_ONESHOT"} ,
{IN_ONLYDIR , "IN_ONLYDIR"} ,
{IN_IGNORED , "IN_IGNORED"},
{IN_ISDIR , "IN_ISDIR"},
{IN_Q_OVERFLOW , "IN_Q_OVERFLOW"},
{IN_UNMOUNT , "IN_UNMOUNT"},
};
static void _inotify_event_handler(struct inotify_event *event)
{
int i;
// printf("event->mask: 0x%08x\n", event->mask);
// printf("event->len=%d\n", event->len);
for (i = 0; i < sizeof(event_masks)/sizeof(struct EventMask); ++i)
{
if(event->mask & event_masks[i].flag){
printf("event->name: %s\n", event_masks[i].name);
}
}
}
/*
* timeount 单位ms
*/
static void inotify_select_read(int fd, int timeout)
{
fd_set fds;
struct timeval tv;
struct inotify_event *event=NULL;
char buf[1024] ={0};
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = timeout/1000;
tv.tv_usec = (timeout%1000)*1000;
//监控fd有事件发生
if(select(fd+1, &fds, NULL, NULL, &tv) > 0){
printf("##############################\n");
int len, index=0;
//没有读取到事件
while( (len = read(fd, &buf, sizeof(buf))) < 0 && (errno == EINTR));
while(index < len){
event = (struct inotify_event *)(buf + index);
_inotify_event_handler(event);
index += sizeof(struct inotify_event) + event->len; //移动到下一事件
}
}
}
int main(int argc, char *argv[])
{
//inotify 并不能检测/proc,它是psudo文件系统,是内核提供给用户的一个内核结构的窗口而已
// char file_name[] = "/proc/mounts";
char file_name[] = "/tmp/1.txt";
int fd = inotify_init();
int wd = inotify_add_watch(fd , file_name, IN_ALL_EVENTS);
while(1){
inotify_select_read(fd ,2000);
}
inotify_rm_watch(fd, wd);
return 0;
}