首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

fanotify 监控文件系统(6)

fanotify 监控文件系统(6)

主循环,等待事件基本的等待事件循环如下所示:
清单 7. 等待事件循环
1
2
3
4
5
6
7
8
9
10
11
12
FD_ZERO(&rfds);
FD_SET(fan_fd, &rfds);
select(fan_fd+1, &rfds, NULL, NULL, NULL);
while ((len = read(fan_fd, buf, sizeof(buf))) > 0) {
  。。。
  while(FAN_EVENT_OK(metadata, len)) {
  // 处理 metadata
  . . .
  metadata = FAN_EVENT_NEXT(metadata, len); // 读取下一个 metadata
  }
select(fan_fd+1, &rfds, NULL, NULL, NULL)
}




Fanotify_init 返回的 file descriptor 可以适用于所有文件系统调用。因此可以方便地使用 read 来等待时间;同样,也可以调用 select 同时等待多个 fd 上的事件。因此基本的事件等待循环如代码清单 7 所示。
处理 metadata每一个事件都由一个 metadata 数据结构所表示。
应用程序通过调用 fanotify_init 和 fanotify_mark 设置好需要监控的对象和事件之后,便可以不断地调用 read 轮询是否有文件系统事件发生了。每一个文件系统事件,都由下面这个数据结构表示。
清单 8. 数据结构
1
2
3
4
5
6
7
8
9
struct fanotify_event_metadata {
    __u32 event_len;
    __u8 vers;
    __u8 reserved;
    __u16 metadata_len;
    __aligned_u64 mask;
    __s32 fd;
    __s32 pid;
};




这个数据结构类似于 inotify 中的 inotify_event,其中我们最常使用的数据成员是:
  • fd -- 一个 open fd,代表触发事件的文件系统对象
  • pid  -- 触发文件系统对象的进程 id
  • mask  -- 事件 mask,通过判断 mask,我们可以获知发生了什么事件,比如 OPEN,ACCESS 等。
不同的事件处理通过分析 metadata,我们可以确切地获知当前发生的事件类型。因此一般地,我们可以用一个分支语句结构对不同的事件进行不同的处理,代码如下:
清单 9. 分支语句结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if (metadata->mask & FAN_ACCESS)
    printf(" access");
if (metadata->mask & FAN_OPEN)
    printf(" open");
if (metadata->mask & FAN_MODIFY)
    printf(" modify");
if (metadata->mask & FAN_CLOSE) {
    if (metadata->mask & FAN_CLOSE_WRITE)
        printf(" close(writable)");
    if (metadata->mask & FAN_CLOSE_NOWRITE)
        printf(" close");
}
if (metadata->mask & FAN_OPEN_PERM)
    printf(" open_perm");
if (metadata->mask & FAN_ACCESS_PERM)
    printf(" access_perm");
if (metadata->mask & FAN_ALL_PERM_EVENTS) {
    if (opt_sleep)
        sleep(opt_sleep);
        if (handle_perm(fan_fd, metadata))
        goto fail;
    if (metadata->fd >= 0 &&
       opt_ignore_perm &&
       set_ignored_mask(fan_fd, metadata->fd,
                metadata->mask))
        goto fail;
}




判断 mask 域,如果是 OPEN,则打印 open。看懂了些 if 语句之后,您便可以执行不同于打印的其他您想要的操作了。
Access Descision相比于 inotify,fanotify 还可以进行 Access Decision,当发生 OPEN_PERM/ACCESS_PERM 事件时,监控进程可以通过向内核 fanotify file descriptor 回写一个数据来允许或者拒绝文件操作。该数据为:
1
2
3
4
struct fanotify_response {
    __s32 fd;
    __u32 response;
};




其中,fd 代表将被打开的文件系统对象的 fd;
response 代表是否允许操作的决定,可以选择的值为:
  • FAN_ALLOW,即允许
  • FAN_DENY,即拒绝
进行访问控制决策的函数例子代码如下:
清单 10. 访问控制决策的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int handle_perm(int fan_fd, struct fanotify_event_metadata *metadata)
{
    struct fanotify_response response_struct;
    int ret;

    response_struct.fd = metadata->fd;
    response_struct.response = FAN_ALLOW;

    ret = write(fan_fd, &response_struct, sizeof(response_struct));
    if (ret < 0)
        return ret;

    return 0;
}




在 Eric 的例子中,总是允许该文件操作。因此 handle_perm 函数中没有做任何特殊处理,只是回复一个 FAN_ALLOW。下面我将修改这里的逻辑,让我们更清晰地理解访问控制是如何具体工作的吧。
返回列表