fanotify_init – 初始化fanotify监控实例
fanotify_init
是一个Linux系统调用,用于创建和初始化fanotify文件系统监控实例。fanotify是Linux内核提供的高级文件系统事件监控机制,可以监控文件访问、修改等事件。
函数原型
#include <sys/fanotify.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <fcntl.h>
int fanotify_init(unsigned int flags, unsigned int event_f_flags);
功能
创建一个新的fanotify监控实例,返回文件描述符用于后续的监控操作。
参数
unsigned int flags
: fanotify实例标志FAN_CLASS_NOTIF
: 仅通知类事件FAN_CLASS_CONTENT
: 内容监控类事件FAN_CLASS_PRE_CONTENT
: 预内容监控类事件FAN_CLOEXEC
: 设置执行时关闭标志FAN_NONBLOCK
: 设置非阻塞模式FAN_UNLIMITED_QUEUE
: 无限制队列大小FAN_UNLIMITED_MARKS
: 无限制标记数量
unsigned int event_f_flags
: 事件文件描述符标志O_RDONLY
: 只读打开事件文件O_WRONLY
: 只写打开事件文件O_RDWR
: 读写打开事件文件O_LARGEFILE
: 支持大文件O_CLOEXEC
: 执行时关闭
返回值
- 成功时返回fanotify文件描述符(非负整数)
- 失败时返回-1,并设置errno
特殊限制
- 需要Linux 2.6.39以上内核支持
- 需要CAP_SYS_ADMIN能力
- 某些标志需要特定内核版本
相似函数
fanotify_mark()
: 添加监控标记read()
: 读取fanotify事件inotify_init()
: 旧版文件监控机制
示例代码
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/fanotify.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
// 系统调用包装
static int fanotify_init_wrapper(unsigned int flags, unsigned int event_f_flags) {
return syscall(__NR_fanotify_init, flags, event_f_flags);
}
// 读取fanotify事件
int read_fanotify_events(int fanotify_fd) {
char buffer[4096];
ssize_t len;
struct fanotify_event_metadata *metadata;
len = read(fanotify_fd, buffer, sizeof(buffer));
if (len == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return 0; // 非阻塞模式下无事件
}
perror("读取fanotify事件失败");
return -1;
}
metadata = (struct fanotify_event_metadata *)buffer;
while (FAN_EVENT_OK(metadata, len)) {
if (metadata->vers != FANOTIFY_METADATA_VERSION) {
fprintf(stderr, "不支持的元数据版本\n");
return -1;
}
printf("事件: fd=%d, mask=0x%x, pid=%d\n",
metadata->fd, metadata->mask, metadata->pid);
// 获取文件路径
if (metadata->fd != FAN_NOFD) {
char path[PATH_MAX];
char proc_path[64];
snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", metadata->fd);
ssize_t path_len = readlink(proc_path, path, sizeof(path) - 1);
if (path_len != -1) {
path[path_len] = '\0';
printf(" 文件路径: %s\n", path);
}
close(metadata->fd);
}
metadata = FAN_EVENT_NEXT(metadata, len);
}
return 0;
}
int main() {
int fanotify_fd;
int result;
printf("=== Fanotify_init 函数示例 ===\n");
printf("当前用户 UID: %d\n", getuid());
printf("当前有效 UID: %d\n", geteuid());
// 示例1: 基本使用
printf("\n示例1: 基本使用\n");
// 需要root权限或CAP_SYS_ADMIN能力
fanotify_fd = fanotify_init_wrapper(FAN_CLASS_NOTIF, O_RDONLY);
if (fanotify_fd == -1) {
if (errno == EPERM) {
printf("权限不足创建fanotify实例: %s\n", strerror(errno));
printf("说明: 需要root权限或CAP_SYS_ADMIN能力\n");
} else {
printf("创建fanotify实例失败: %s\n", strerror(errno));
}
printf("在root权限下重新运行此程序以查看完整功能\n");
return 0;
}
printf("成功创建fanotify实例,文件描述符: %d\n", fanotify_fd);
// 检查文件描述符属性
int flags = fcntl(fanotify_fd, F_GETFD);
if (flags != -1) {
printf("fanotify文件描述符验证成功\n");
}
// 关闭fanotify实例
close(fanotify_fd);
printf("关闭fanotify实例\n");
// 示例2: 使用不同标志
printf("\n示例2: 使用不同标志\n");
// 使用FAN_CLOEXEC标志
fanotify_fd = fanotify_init_wrapper(FAN_CLASS_NOTIF | FAN_CLOEXEC, O_RDONLY);
if (fanotify_fd != -1) {
printf("使用FAN_CLOEXEC标志创建成功: %d\n", fanotify_fd);
// 验证CLOEXEC标志
flags = fcntl(fanotify_fd, F_GETFD);
if (flags != -1 && (flags & FD_CLOEXEC)) {
printf("FAN_CLOEXEC标志已正确设置\n");
}
close(fanotify_fd);
}
// 使用FAN_NONBLOCK标志
fanotify_fd = fanotify_init_wrapper(FAN_CLASS_NOTIF | FAN_NONBLOCK, O_RDONLY);
if (fanotify_fd != -1) {
printf("使用FAN_NONBLOCK标志创建成功: %d\n", fanotify_fd);
// 测试非阻塞特性
char buffer[1024];
ssize_t result = read(fanotify_fd, buffer, sizeof(buffer));
if (result == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
printf("非阻塞读取正确返回EAGAIN\n");
}
}
close(fanotify_fd);
}
// 示例3: 不同类别的fanotify实例
printf("\n示例3: 不同类别的fanotify实例\n");
printf("fanotify类别说明:\n");
// FAN_CLASS_NOTIF - 通知类
fanotify_fd = fanotify_init_wrapper(FAN_CLASS_NOTIF, O_RDONLY);
if (fanotify_fd != -1) {
printf("FAN_CLASS_NOTIF (通知类) 创建成功\n");
printf(" - 仅接收通知事件\n");
printf(" - 不需要响应事件\n");
printf(" - 权限要求较低\n");
close(fanotify_fd);
}
// FAN_CLASS_CONTENT - 内容监控类
fanotify_fd = fanotify_init_wrapper(FAN_CLASS_CONTENT, O_RDONLY);
if (fanotify_fd != -1) {
printf("FAN_CLASS_CONTENT (内容监控类) 创建成功\n");
printf(" - 可以读取文件内容\n");
printf(" - 需要更高权限\n");
close(fanotify_fd);
}
// FAN_CLASS_PRE_CONTENT - 预内容监控类
fanotify_fd = fanotify_init_wrapper(FAN_CLASS_PRE_CONTENT, O_RDONLY);
if (fanotify_fd != -1) {
printf("FAN_CLASS_PRE_CONTENT (预内容监控类) 创建成功\n");
printf(" - 可以在操作前拦截\n");
printf(" - 需要最高权限\n");
close(fanotify_fd);
}
// 示例4: 错误处理演示
printf("\n示例4: 错误处理演示\n");
// 使用无效标志
fanotify_fd = fanotify_init_wrapper(0x1000, O_RDONLY);
if (fanotify_fd == -1) {
if (errno == EINVAL) {
printf("无效标志错误处理正确: %s\n", strerror(errno));
}
}
// 使用无效的event_f_flags
fanotify_fd = fanotify_init_wrapper(FAN_CLASS_NOTIF, 0x1000);
if (fanotify_fd == -1) {
if (errno == EINVAL) {
printf("无效event_f_flags错误处理正确: %s\n", strerror(errno));
}
}
// 示例5: 权限和能力说明
printf("\n示例5: 权限和能力说明\n");
printf("fanotify权限要求:\n");
printf("FAN_CLASS_NOTIF:\n");
printf(" - 需要对监控目录的读权限\n");
printf(" - 一般用户可使用\n\n");
printf("FAN_CLASS_CONTENT:\n");
printf(" - 需要CAP_SYS_ADMIN能力\n");
printf(" - 或root权限\n\n");
printf("FAN_CLASS_PRE_CONTENT:\n");
printf(" - 需要CAP_SYS_ADMIN能力\n");
printf(" - 或root权限\n");
printf(" - 最高权限级别\n\n");
// 示例6: 实际使用场景
printf("示例6: 实际使用场景\n");
printf("fanotify典型应用场景:\n");
printf("1. 文件完整性监控\n");
printf("2. 入侵检测系统\n");
printf("3. 文件访问审计\n");
printf("4. 实时备份系统\n");
printf("5. 安全策略执行\n");
printf("6. 系统监控工具\n\n");
// 示例监控代码框架
printf("基本监控代码框架:\n");
printf("int setup_file_monitoring(const char* path) {\n");
printf(" int fanotify_fd = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY);\n");
printf(" if (fanotify_fd == -1) return -1;\n");
printf(" \n");
printf(" // 添加监控标记\n");
printf(" if (fanotify_mark(fanotify_fd, FAN_MARK_ADD, \n");
printf(" FAN_OPEN | FAN_CLOSE_WRITE,\n");
printf(" AT_FDCWD, path) == -1) {\n");
printf(" close(fanotify_fd);\n");
printf(" return -1;\n");
printf(" }\n");
printf(" \n");
printf(" return fanotify_fd;\n");
printf("}\n\n");
// 示例7: 事件处理循环
printf("示例7: 事件处理循环\n");
printf("fanotify事件处理循环示例:\n");
printf("void monitor_files(int fanotify_fd) {\n");
printf(" struct pollfd pfd = {.fd = fanotify_fd, .events = POLLIN};\n");
printf(" \n");
printf(" while (running) {\n");
printf(" int ret = poll(&pfd, 1, 1000); // 1秒超时\n");
printf(" if (ret > 0 && (pfd.revents & POLLIN)) {\n");
printf(" handle_fanotify_events(fanotify_fd);\n");
printf(" }\n");
printf(" }\n");
printf("}\n\n");
// 示例8: 与inotify的对比
printf("示例8: 与inotify的对比\n");
printf("fanotify vs inotify:\n");
printf("fanotify优势:\n");
printf(" - 可以监控整个文件系统\n");
printf(" - 支持文件内容访问监控\n");
printf(" - 可以获取文件描述符\n");
printf(" - 支持权限检查\n");
printf(" - 更高的性能\n\n");
printf("inotify优势:\n");
printf(" - 更广泛的内核支持\n");
printf(" - 更简单的API\n");
printf(" - 更低的权限要求\n");
printf(" - 更好的可移植性\n\n");
// 示例9: 性能和资源考虑
printf("示例9: 性能和资源考虑\n");
printf("fanotify性能特点:\n");
printf("1. 内核级实现,性能优秀\n");
printf("2. 批量事件处理\n");
printf("3. 可配置的队列大小\n");
printf("4. 低CPU开销\n\n");
printf("资源使用考虑:\n");
printf("1. 每个实例消耗内核资源\n");
printf("2. 事件队列有大小限制\n");
printf("3. 及时处理事件避免队列溢出\n");
printf("4. 合理设置监控范围\n\n");
// 示例10: 安全考虑
printf("示例10: 安全考虑\n");
printf("使用fanotify的安全注意事项:\n");
printf("1. 需要适当权限\n");
printf("2. 避免监控敏感目录\n");
printf("3. 及时关闭不需要的实例\n");
printf("4. 处理事件时注意安全\n");
printf("5. 防止事件处理中的拒绝服务\n");
printf("6. 限制监控的文件数量\n\n");
printf("总结:\n");
printf("fanotify_init是创建fanotify监控实例的基础函数\n");
printf("提供了比inotify更强大的文件监控能力\n");
printf("需要适当的权限和能力\n");
printf("支持多种监控类别和标志\n");
printf("是构建高级文件监控应用的重要工具\n");
return 0;
}