根据 inotify 自己开发软件监控文件系统活动
了解 inotify
Inotify 是一个 Linux 内核特性,它监控文件系统,并且及时向专门的应用程序发出相关的事件警告,比如删除、读、写和卸载操作等。您还可以跟踪活动的源头和目标等细节。
使用 inotify 很简单:创建一个文件描述符,附加一个或多个监视器(一个监视器 是一个路径和一组事件),然后使用 read() 方法从描述符获取事件信息。read() 并不会用光整个周期,它在事件发生之前是被阻塞的。
更好的是,因为 inotify 通过传统的文件描述符工作,您可以利用传统的 select() 系统调用来被动地监控监视器和许多其他输入源。两种方法 — 阻塞文件描述符和使用 select()— 都避免了繁忙轮询。
现在,让我们深入了解 inotify,写一些 C 代码,然后看看一组命令行工具,您可以构建并使用它们将命令和脚本附加到文件系统事件。Inotify 不会在中途失去控制,但它可以运行 cat 和 wget,并且在必要时严格执行。
要使用 inotify,您必须具备一台带有 2.6.13 或更新内核的 Linux 机器(以前的 Linux 内核版本使用更低级的文件监控器 dnotify)。如果您不知道内核的版本,请转到 shell,输入 uname -a:
% uname -a
Linux ubuntu-desktop 2.6.24-19-generic #1 SMP ... i686 GNU/Linux
如果列出的内核版本不低于 2.6.13,您的系统就支持 inotify。您还可以检查机器的 /usr/include/sys/inotify.h 文件。如果它存在,表明您的内核支持 inotify。
注意:FreeBSD 和 Mac OS X 提供一个类似于 inotify 的 kqueue。在 FreeBSD 机器上输入 man 2 kqueue 获取更多信息。
本文基于 Ubuntu Desktop version 8.04.1(即 Hardy),它运行在 Mac OS X version 10.5 Leopard 的 Parallels Desktop version 3.0。
inotify C API
Inotify 提供 3 个系统调用,它们可以构建各种各样的文件系统监控器:
inotify_init() 在内核中创建 inotify 子系统的一个实例,成功的话将返回一个文件描述符,失败则返回 -1。就像其他系统调用一样,如果 inotify_init() 失败,请检查 errno 以获得诊断信息。
顾名思义,inotify_add_watch() 用于添加监视器。每个监视器必须提供一个路径名和相关事件的列表(每个事件由一个常量指定,比如
IN_MODIFY)。要监控多个事件,只需在事件之间使用逻辑操作符或 — C 语言中的管道线(|)操作符。如果
inotify_add_watch() 成功,该调用会为已注册的监视器返回一个惟一的标识符;否则,返回
-1。使用这个标识符更改或删除相关的监视器。
inotify_rm_watch() 删除一个监视器。
此外,还需要 read()
和 close() 系统调用。如果描述符由 inotify_init() 生成,则调用 read()
等待警告。假设有一个典型的文件描述符,应用程序将阻塞对事件的接收,这些事件在流中表现为数据。文件描述符上的由 inotify_init()
生成的通用 close() 删除所有活动监视器,并释放与 inotify
实例相关联的所有内存(这里也用到典型的引用计数警告。与实例相关联的所有文件描述符必须在监视器和 inotify 消耗的内存被释放之前关闭)。
这个强大的工具提供 3 个应用程序编程接口(API)调用,以及简单、熟悉的范例 “所有内容都是文件”。现在,我们看看示例应用程序。
示例应用程序:事件监控
清单 1 是一个监控两个事件的目录的简短 C 程序:文件的创建和删除。
清单 1. 简单的 inotify 应用程序,它监控创建、删除和修改事件的目录
#include
#include
#include
#include <sys/types.h>
#include <sys/inotify.h>
#define EVENT_SIZE ( sizeof (struct inotify_event) )
#define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
int main( int argc, char **argv )
{
int length, i = 0;
int fd;
int wd;
char buffer[BUF_LEN];
fd = inotify_init();
if ( fd < 0 ) {
perror( "inotify_init" );
}
wd = inotify_add_watch( fd, "/home/strike",
IN_MODIFY | IN_CREATE | IN_DELETE );
length = read( fd, buffer, BUF_LEN );
if ( length < 0 ) {
perror( "read" );
}
while ( i < length ) { struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ]; if ( event->len ) {
if ( event->mask & IN_CREATE ) {
if ( event->mask & IN_ISDIR ) {
printf( "The directory %s was created.\n", event->name );
}
else {
printf( "The file %s was created.\n", event->name );
}
}
else if ( event->mask & IN_DELETE ) {
if ( event->mask & IN_ISDIR ) {
printf( "The directory %s was deleted.\n", event->name );
}
else {
printf( "The file %s was deleted.\n", event->name );
}
}
else if ( event->mask & IN_MODIFY ) {
if ( event->mask & IN_ISDIR ) {
printf( "The directory %s was modified.\n", event->name );
}
else {
printf( "The file %s was modified.\n", event->name );
}
}
}
i += EVENT_SIZE + event->len;
}
( void ) inotify_rm_watch( fd, wd );
( void ) close( fd );
exit( 0 );
}
这个应用程序通过 fd = inotify_init(); 创建一个 inotify 实例,并添加一个监视器来监控修改、新文件和
/home/strike 中的损坏文件(由 wd = inotify_add_watch(...) 指定)。read()
方法在一个或多个警告到达之前是被阻塞的。警告的详细内容 — 每个文件、每个事件 —
是以字节流的形式发送的;因此,应用程序中的循环将字节流转换成一系列事件结构。
在文件 /usr/include/sys/inotify.h. 中,您可以找到事件结构的定义,它是一种 C 结构,如清单 2 所示。
清单 2. 事件结构的定义
struct inotify_event
{
int wd; /* The watch descriptor */
uint32_t mask; /* Watch mask */
uint32_t cookie; /* A cookie to tie two events together */
uint32_t len; /* The length of the filename found in the name field */
char name __flexarr; /* The name of the file, padding to the end with NULs */
}
wd 字段是指与事件相关联的监视器。如果每个 inotify 有一个以上的实例,您可以使用这个字段确定如何继续以后的处理过程。mask 字段由几个部分组成,它说明发生的事情。分别测试每个部分。
当把一个文件从一个目录移动到另一个目录时,您可以使用 cookie 将两个事件绑在一起。仅当您监视源和目标目录时,inotify
才生成两个移动事件 — 分别针对源和目标 —,并通过设置 cookie 将它们绑定在一起。要监视一个移动操作,必须指定
IN_MOVED_FROM 或 IN_MOVED_TO,或使用简短的 IN_MOVE,它可以监视两个操作。使用 IN_MOVED_FROM 和
IN_MOVED_TO 来测试事件类型。
最后,name 和 len 包含文件的名称(但不包括路径)和受影响文件的名称的长度。
构建示例应用程序代码
要构建这些代码,请将目录 /home/strike 更改到您的主目录,即将这些代码保存到一个文件中,然后调用 C 编译器 — 在大部分 Linux 系统中为 gcc。然后,运行这个可执行文件,如清单 3 所示。
清单 3. 运行可执行文件
% cc -o watcher watcher.c
% ./watcher
在监视程序运行时,打开第二个终端窗口并使用 touch、cat 和 rm 来更改主目录的内容,如清单 4 所示。完成之后,重新启动您的新应用程序。
清单 4. 使用 touch、cat 和 rm
% cd $HOME
% touch a b c
The file a was created.
The file b was created.
The file c was created.
% ./watcher &
% rm a b c
The file a was deleted.
The file b was deleted.
The file c was deleted.
% ./watcher &
% touch a b c
The file a was created.
The file b was created.
The file c was created.
% ./watcher &
% cat /etc/passwd >> a
The file a was modified.
% ./watcher &
% mkdir d
The directory d was created.
试用其他可用的监视标志。要捕捉权限的更改,请将 IN_ATTRIB 添加到 mask。
使用 inotify 的技巧
您还可以使用 select()、pselect()、poll() 和 epoll()
来避免阻塞。如果您想将监视器的监控作为图形应用程序的主事件处理循环的一部分,或作为监视其他输入连接的守护进程的一部分,这是很有用的。将该
inotify 描述符添加到这组描述符中,进行并发监控。清单 5 展示了 select() 的标准形式。
清单 5. select() 的标准形式
int return_value;
fd_set descriptors;
struct timeval time_to_wait;
FD_ZERO ( &descriptors );
FD_SET( ..., &descriptors );
FD_SET ( fd, &descriptors );
...
time_to_wait.tv_sec = 3;
time.to_waittv_usec = 0;
return_value = select ( fd + 1, &descriptors, NULL, NULL, &time_to_wait);
if ( return_value < 0 ) {
/* Error */
}
else if ( ! return_value ) {
/* Timeout */
}
else if ( FD_ISSET ( fd, &descriptors ) ) {
/* Process the inotify events */
...
}
else if ...
select() 方法在 time_to_wait 期间暂停程序。然而,如果在这个延迟期间这组描述符的任意一个文件描述符发生活动,将立即恢复执行程序。否则,调用就会超时,允许应用程序执行其他进程,比如在图形用户界面(GUI)工具中响应鼠标或键盘事件。
下面是使用 inotify 的其他技巧:
如果监视中的文件或目录被删除,它的监视器也会被自动删除(在删除事件发出之后)。
如果在已卸载的文件系统上监控文件或目录,监视器将在删除所有受影响的监视之前收到一个卸载事件。
将 IN_ONESHOT 标志添加到监视器标记中,设置一个一次性警告。警告在发送之后将被删除。
要修改一个事件,必须提供相同的路径名和不同的标记。新监视器将取代老监视器。
考虑到实用性,不可能耗尽任何一个 inotify 实例的监视器。然而,您可能会耗尽事件队列的空间,这取决于处理事件的频率。队列溢出会引起 IN_Q_OVERFLOW 事件。
close() 方法毁坏 inotify 实例和所有相关联的监视器,并清空队列中的所有等待事件。
根据 inotify 自己开发软件监控文件系统活动的更多相关文章
- php使用inotify扩展监控文件或目录的变化
一.安装inotify扩展 1.下载inotify扩展源码 https://pecl.php.net/package/inotify 对于php7以上版本,请下载 inotify-2.0.0.tgz. ...
- (转)Linux下通过rsync与inotify(异步文件系统事件监控机制)实现文件实时同步
Linux下通过rsync与inotify(异步文件系统事件监控机制)实现文件实时同步原文:http://www.summerspacestation.com/linux%E4%B8%8B%E9%80 ...
- php使用inotify扩展监控文件或目录,如果发生改变,就执行指定命令
通过inotify扩展监控文件或目录的变化,如果发生变化,就执行命令. 可以应用于 swoole 中,如果文件发生变化,就执行 kill -USR1 进程PID 来实现热更新. <?php cl ...
- [转帖]Linux下inotify监控文件夹状态,发生变化后触发rsync同步
Linux下inotify监控文件夹状态,发生变化后触发rsync同步 https://www.cnblogs.com/fjping0606/p/6114123.html 1.安装工具--inotif ...
- python软件开发规范&分文件对于后期代码的高效管理
根据本人的学习,按照理解整理和补充了python模块的相关知识,希望对于一些需要了解的python爱好者有帮助! 一.软件开发规范--分文件 当代码存在一个py文件中时: 1.不便于管理 (修改,增加 ...
- Hi3559AV100 NNIE开发(3)RuyiStudio软件 .wk文件生成过程-mobilefacenet.cfg的参数配置
之后随笔将更多笔墨着重于NNIE开发系列,下文是关于Hi3559AV100 NNIE开发(3)RuyiStudio软件 .wk文件生成过程-mobilefacenet.cfg的参数配置,目前项目需要对 ...
- 使用inotify+rsync实现服务器间文件同步
1. rsync 1.1 什么是rsync rsync是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件.它使用所谓的“Rsync演算法”来使本地和远程两个主机之间的文件达到 ...
- Web开发安全之文件上传安全
很长一段时间像我这种菜鸡搞一个网站第一时间反应就是找上传,找上传.借此机会把文件上传的安全问题总结一下. 首先看一下DVWA给出的Impossible级别的完整代码: <?php if( iss ...
- 使用FileSystemWatcher监控文件夹及文件
引言 这一周主要精力集中学习一个同事开发的本地文件搜索项目上,其中客户端添加共享文件时主要是使用FileSystemWatcher 监控文件,并在各种事件发生时向服务器发送消息. 解决方法 FileS ...
随机推荐
- Java集合源码分析(三)Vevtor和Stack
前言 前面写了一篇关于的是LinkedList的除了它的数据结构稍微有一点复杂之外,其他的都很好理解的.这一篇讲的可能大家在开发中很少去用到.但是有的时候也可能是会用到的! 注意在学习这一篇之前,需要 ...
- [51nod1743]雪之国度
雪之国度有N座城市,依次编号为1到N,又有M条道路连接了其中的城市,每一条道路都连接了不同的2个城市,任何两座不同的城市之间可能不止一条道路. 雪之女王赋予了每一座城市不同的能量,其中第i座城市被赋予 ...
- [bzoj3702] 二叉树
一个节点的儿子是否交换,不会影响到它和兄弟节点间的逆序对数. 所以每次合并线段树的时候算一下交换与不交换的逆序对数,然后选个较小值就行了. #include<cstdio> #includ ...
- UOJ#152. 【UR #10】汉诺塔
题目:http://uoj.ac/problem/152 orzKPM... 分治,把数字是l~mid的拿出来放在一根柱子上,mid+1~r放在另一根柱子上.如此递归下去,每次递归只是改一下方向,l, ...
- JXLS 2.4.0系列教程(六)番外篇——导出图片(完结)
突然想起来有同学说过能不能导出图片,本来我是想说不懂的,后来我上官网查了查,还挺容易.我就简短的写一写怎么导出图片. 官方提供了导出图片标签: jx:image(lastCell="D10& ...
- [国嵌攻略][098][Linux内核简介]
Linux系统架构 1.用户空间:应用程序.C函数库 2.内核空间:系统调用接口.内核.体系结构相关代码 Linux系统利用处理器不同的工作模式,使用其中的两个级别分别来运行Linux内核与应用程序, ...
- Anndroid 使用相机或相册打开图片
安卓操作相机or相册 笔者做这方面测试的时候,没遇到什么大坑基本上,需要注意的有两点 1. 使用相册打开读取图片需要使用运行时权限,而且还是要在AndroidManifest.xml中进行权限声明 ...
- 【学习笔记】Java finalize()的使用
<Java编程思想>中有提到,Java的垃圾回收器并不是那么靠谱,垃圾回收会占用很大的资源开销,垃圾回收器很懒,当变量和对象不再被引用.脱离作用域的时候,垃圾回收器会不定时的进行垃圾回收, ...
- 怎么从一台电脑的浏览器输入地址访问另一台电脑服务器(WAMP服务器已搭建,PHPSTORM装好了)
服务器电脑WAMP环境搭建好了,浏览器输入LOCALHOST就能访问本地 WAMP/WWW 目录下PHP文件,怎么样才能从另一台电脑通过浏览器访问呢?求详细步骤... glwbdtb | 浏览 180 ...
- C#编写街道管理系统
项目需求: 一.语言和环境 A.实现语言 C# B.环境要求 Visual Studio 2012 二.功能要求 现使用.NET WinForms技术为居委会开发一个街道管理软件,其中街道管理窗体界面 ...