Chinaunix首页 | 论坛 | 博客
  • 博客访问: 962746
  • 博文数量: 109
  • 博客积分: 554
  • 博客等级: 中士
  • 技术积分: 2577
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-04 12:49
文章分类

全部博文(109)

文章存档

2019年(5)

2016年(7)

2015年(9)

2014年(1)

2013年(71)

2012年(16)

分类: 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

 

用于 inotify 的事件结构体

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可以检测的事件类型

适用于 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;
}

阅读(4016) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~