Linux下文件系统事件监听-inotify

2024-03-10 05:18

本文主要是介绍Linux下文件系统事件监听-inotify,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

从文件管理器到安全工具,文件系统监控对于的许多程序来说都是必不可少的。从 Linux 2.6.13 内核开始,Linux 就推出了 inotify,允许监控程序打开一个独立文件描述符,并针对事件集监控一个或者多个文件,例如打开、关闭、移动/重命名、删除、创建或者改变属性。在后期的内核中有了很多增强,因此在依赖这些特性之前,请先检查您的内核版本。

在 inotify 之前有 dnotify。不幸的是,dnotify 有局限性,用户需要更好的产品。和 dnotify 相比 inotify 的优势如下:

1. notify 使用一个独立的文件描述符,而 dnotify 需要为每个受监控的目录打开一个文件描述符。当您同时监控多个目录时成本会非常高,而且还会遇到每进程文件描述符限制。

2. Inotify 所使用的文件描述符可以通过系统调用获得,并且没有相关设备或者文件。而使用 dnotify,文件描述符就固定了目录,妨碍备用设备卸载,这是可移动媒体的一个典型问题。对于 inotify,卸载的文件系统上的监视文件或目录会产生一个事件,而且监视也会自动移除。

3. Inotify 能够监视文件或者目录。Dnotify 则只监视目录,因此程序员还必须保持 stat 结构或者一个等效的数据结构,来反映该被监视目录中的文件,然后在一个事件发生时,将其与当前状态进行对比,以此了解当前目录中的条目发生了什么情况。

4. inotify 使用文件描述符,允许程序员使用标准 select 或者 poll 函数来监视事件。这允许高效的多路复用 I/O 或者与 Glib 的 mainloop 的集成。相比之下,dnotify 使用信号,这使得程序员觉得比较困难或者不够流畅。在 2.6.25 内核中 inotify 还添加了 Signal-drive I.O 通知功能。

 

inotify的使用步骤:

 

1. 创建 inotify 实例

int fd =inotify_init (void);

每一个 inotify 实例对应一个独立的排序的队列。 
文件系统的变化事件被称做 watches 的一个对象管理,每一个 watch 是一个二元组(目标,事件掩码),目标可以是文件或目录,事件掩码表示应用希望关注的 inotify 事件,每一个位对应一个 inotify 事件。Watch 对象通过 watch描述符引用,watches 通过文件或目录的路径名来添加。目录 watches 将返回在该目录下的所有文件上面发生的事件。

2. 添加一个 watch

int wd= inotify_add_watch (int fd, constchar *path, __u32 mask);

fd 是inotify_init() 返回的文件描述符,path 是被监视的目标的路径名(即文件名或目录名),mask 是事件掩码, 在头文件 linux/inotify.h 中定义了每一位代表的事件。可以使用同样的方式来修改事件掩码,即改变希望被通知的inotify 事件。Wd 是 watch 描述符。

可以被监控的事件:

事件

描述

IN_ACCESS

File was  accessed

IN_MODIFY

File was  modified

IN_ATTRIB

Metadata  changed

IN_CLOSE_WRITE

Writtable file  was closed

IN_CLOSE_NOWRITE

Unwrittable  file closed

IN_OPEN

File was opened

IN_MOVED_FROM

File was moved  from X

IN_MOVED_TO

File was moved  to Y

IN_CREATE

Subfile was  created

IN_DELETE

Subfile was  deleted

IN_DELETE_SELF

Self was  deleted

IN_MOVE_SELF

Self was moved

IN_UNMOUNT

Backing fs was  unmounted

IN_Q_OVERFLOW

Event queued  overflowed

IN_IGNORED

File was  ignored

IN_CLOSE

(IN_CLOSE_WRITE  | IN_CLOSE_NOWRITE) /* close */

IN_MOVE

(IN_MOVED_FROM  | IN_MOVED_TO) /* moves */

IN_ONLYDIR

only watch the  path if it is a directory

IN_DONT_FOLLOW

don't follow a  sym link

IN_MASK_ADD

add to the mask  of an already existing watch

IN_ISDIR

event occurred  against dir

IN_ONESHOT

only send event  once


与添加对应的是删除一个watch:

int ret =inotify_rm_watch (int fd, __u32 mask);

fd inotify_init() 返回的文件描述符,wd inotify_add_watch() 返回的 watch 描述符。Ret 是函数的返回值。

3. 等待事件:

使用标准 select 或者 poll 函数来监控inotify ,当被监视的目标有指定的事件发生时select 或者 poll 会返回。

4.获取事件:

文件事件用一个inotify_event 结构表示,它通过由inotify_init() 返回的文件描述符使用通常文件读取函数 read 来获得。

structinotify_event {

        __s32           wd;             /* watch descriptor */

        __u32           mask;           /* watch mask */

        __u32           cookie;         /* cookie to synchronize two events */

        __u32           len;            /* length (including nulls) of name*/

        char            name[0];        /* stub for possible name */

};

 

结构中的 wd 为被监视目标的 watch 描述符,mask 为事件掩码,len 为 name字符串的长度,name 为被监视目标的路径名,该结构的 name 字段为一个桩,它只是为了用户方面引用文件名,文件名是变长的,它实际紧跟在该结构的后面,文件名将被 0 填充以使下一个事件结构能够 4 字节对齐。注意,len 也把填充字节数统计在内。

size_t len =read (fd, buf, BUF_LEN);

通过 read 调用可以一次获得多个事件,只要提供的 buf 足够大。 
buf 是一个 inotify_event 结构的数组指针,BUF_LEN 指定要读取的总长度,buf 大小至少要不小于 BUF_LEN,该调用返回的事件数取决于 BUF_LEN 以及事件中文件名的长度。Len 为实际读去的字节数,即获得的事件的总长度。

5. 处理事件:

根据获取的事件类型做相对应的处理。

6. 停止监控:

close(fd)将删除所有添加到 fd 中的 watch 并做必要的清理。

一个简单的例子:

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<sys/inotify.h>

 

struct wd_path

{

    int wd;

    char *path;

};

char *event_array[] = {

"File wasaccessed",

"File wasmodified",

"Fileattributes were changed",

"writtablefile closed",

"Unwrittablefile closed",

"File wasopened",

"File wasmoved from X",

"File wasmoved to Y",

"Subfile wascreated",

"Subfile wasdeleted",

"Self wasdeleted",

"Self wasmoved",

"",

"Backing fswas unmounted",

"Eventqueued overflowed",

"File wasignored"

};

#define EVENT_NUM16

 

int main(intargc,char *argv[])

{

    int fd,wd,len,tmp_len,i;

    char buffer[1024],*offset,target[1024];

    struct wd_path *wd_array;

    struct inotify_event *event;

    wd_array=(structwd_path*)malloc((argc-1)*sizeof(struct wd_path));

    fd=inotify_init();

    if(-1==fd)

    {

        printf("failed to initinotifyn");

        return 0;

    }

    for(i=0;i<argc-1;i++)

    {

        wd_array[i].path=argv[i+1];

        wd=inotify_add_watch(fd,wd_array[i].path,IN_ALL_EVENTS);

        wd_array[i].wd=wd;

    }

    memset(buffer,0,1024);

    while(len=read(fd,buffer,1024))

    {

        offset=buffer;

        event=(struct inotify_event*)buffer;

        while(((char *)event-buffer)<len)

        {

            for(i=0;i<argc-1;i++)

            {

               if(event->wd==wd_array[i].wd)

                {

                    memset(target,0,1024);

                   strcpy(target,wd_array[i].path);

                    strcat(target,"/");

                   strcat(target,event->name);

                   printf("nnntarget:%s:n",target);

                }

            }

            for(i=0;i<EVENT_NUM;i++)

            {

               if(event->mask&(1<<i))

                    printf("    event:%sn",event_array[i]);

            }

            tmp_len=sizeof(structinotify_event)+event->len;

            event=(structinotify_event*)(offset+tmp_len);

            offset+=tmp_len;

        }

    }

    return 1;

}



这篇关于Linux下文件系统事件监听-inotify的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/793168

相关文章

ubuntu16.04如何部署dify? 在Linux上安装部署Dify的技巧

《ubuntu16.04如何部署dify?在Linux上安装部署Dify的技巧》随着云计算和容器技术的快速发展,Docker已经成为现代软件开发和部署的重要工具之一,Dify作为一款优秀的云原生应用... Dify 是一个基于 docker 的工作流管理工具,旨在简化机器学习和数据科学领域的多步骤工作流。它

Linux高并发场景下的网络参数调优实战指南

《Linux高并发场景下的网络参数调优实战指南》在高并发网络服务场景中,Linux内核的默认网络参数往往无法满足需求,导致性能瓶颈、连接超时甚至服务崩溃,本文基于真实案例分析,从参数解读、问题诊断到优... 目录一、问题背景:当并发连接遇上性能瓶颈1.1 案例环境1.2 初始参数分析二、深度诊断:连接状态与

Linux系统调试之ltrace工具使用与调试过程

《Linux系统调试之ltrace工具使用与调试过程》:本文主要介绍Linux系统调试之ltrace工具使用与调试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、ltrace 定义与作用二、ltrace 工作原理1. 劫持进程的 PLT/GOT 表2. 重定

Linux区分SSD和机械硬盘的方法总结

《Linux区分SSD和机械硬盘的方法总结》在Linux系统管理中,了解存储设备的类型和特性是至关重要的,不同的存储介质(如固态硬盘SSD和机械硬盘HDD)在性能、可靠性和适用场景上有着显著差异,本文... 目录一、lsblk 命令简介基本用法二、识别磁盘类型的关键参数:ROTA查询 ROTA 参数ROTA

什么是ReFS 文件系统? ntfs和refs的优缺点区别介绍

《什么是ReFS文件系统?ntfs和refs的优缺点区别介绍》最近有用户在Win11Insider的安装界面中发现,可以使用ReFS来格式化硬盘,这是不是意味着,ReFS有望在未来成为W... 数十年以来,Windows 系统一直将 NTFS 作为「内置硬盘」的默认文件系统。不过近些年来,微软还在研发一款名

嵌入式Linux之使用设备树驱动GPIO的实现方式

《嵌入式Linux之使用设备树驱动GPIO的实现方式》:本文主要介绍嵌入式Linux之使用设备树驱动GPIO的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、设备树配置1.1 添加 pinctrl 节点1.2 添加 LED 设备节点二、编写驱动程序2.1

嵌入式Linux驱动中的异步通知机制详解

《嵌入式Linux驱动中的异步通知机制详解》:本文主要介绍嵌入式Linux驱动中的异步通知机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、异步通知的核心概念1. 什么是异步通知2. 异步通知的关键组件二、异步通知的实现原理三、代码示例分析1. 设备结构

Linux搭建单机MySQL8.0.26版本的操作方法

《Linux搭建单机MySQL8.0.26版本的操作方法》:本文主要介绍Linux搭建单机MySQL8.0.26版本的操作方法,本文通过图文并茂的形式给大家讲解的非常详细,感兴趣的朋友一起看看吧... 目录概述环境信息数据库服务安装步骤下载前置依赖服务下载方式一:进入官网下载,并上传到宿主机中,适合离线环境

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

windows和Linux使用命令行计算文件的MD5值

《windows和Linux使用命令行计算文件的MD5值》在Windows和Linux系统中,您可以使用命令行(终端或命令提示符)来计算文件的MD5值,文章介绍了在Windows和Linux/macO... 目录在Windows上:在linux或MACOS上:总结在Windows上:可以使用certuti