名称
inotify - 监视文件系统事件
描述
- Inotify可用于监视单个文件或监视目录。
- 监视目录时,inotify将返回目录本身以及目录内文件的事件。
- 目录的Inotify监视不是递归的:要监视目录下的子目录,必须创建其他监视。
- inotify API不提供有关触发inotify事件的用户或进程的信息。
- 通过从inotify文件描述符读取返回的事件形成有序队列。
- 可以使用select(2),poll(2)和epoll(7)监视Inotify文件描述符。当事件可用时,文件描述符表示可读。
- 如果在inotify文件描述符上生成的连续输出inotify事件是相同的(相同的wd,掩码,cookie和名称),那么如果尚未读取旧事件,则它们将合并为单个事件(但请参阅BUGS)。
API
#include <sys/inotify.h>
inotify_init()
inotify_add_watch()
inotify_rm_watch()
- int inotify_init(void)
初始化一个新的inotify实例,返回与新的inotify事件队列关联的文件描述符。
返回值:
成功时,这些系统调用返回一个新的文件描述符。
出错时,返回-1,并设置errno 以指示错误
错误码 | 含义 |
---|---|
EINVAL | (inotify_init1())在flags中指定了无效值。 |
**EMFILE ** | 已达到用户对inotify实例总数的限制。 |
ENFILE | 已达到系统对文件描述符总数的限制。 |
ENOMEM | 内核内存不足。 |
- int inotify_add_watch(int fd, const char *pathname, uint32_t mask);
将wathc添加到初始化的inotify实例;为路径名中指定位置的文件添加新监视或修改现有监视;
fd::参数是文件描述符指的是inotify实例,其观察名单将被修改。
pathname: 被监视文件的或目录的路径,调用者必须具有此文件的读取权限。
mask:要监视路径名的事件在mask bit-mask参数中指定。
返回值:
成功时,inotify_add_watch()返回非负监视描述符。
错误时,返回-1,并正确设置errno。
错误码 | 含义 |
---|---|
EACCES | 不允许对给定文件进行读访问。 |
EBADF | 给定的文件描述符无效。 |
EFAULT | pathname指向进程可访问的地址空间之外。 |
EINVAL | 给定的事件掩码不包含有效事件; 或fd不是inotify文件描述符。 |
ENOENT | 路径名中的目录组件不存在或是悬挂的符号链接。 |
ENOMEM | 内核内存不足。 |
ENOSPC | 达到了用户对inotify监视总数的限制,或者内核无法分配所需的资源 |
- int inotify_rm_watch(int fd, int wd);
从与文件描述符fd关联的inotify实例中删除与监视描述符wd关联的监视。
fd:inotify_init() 返回的inotify 实例
wd:inotify_add_watch()返回的监视描述符
返回值:
成功时,inotify_rm_watch()返回零,
错误时,返回-1(在这种情况下,正确 设置errno)。
错误码 | 含义 |
---|---|
EBADF | fd不是有效的文件描述符。 |
EINVAL | 监视描述符wd无效; 或fd不是inotify文件描述符。 |
数据结构
事件发生后,read函数返回一个包含一个或多个以下结构的buffer
struct inotify_event {
int wd; /* Watch descriptor */
uint32_t mask; /* Mask of events */
uint32_t cookie; /* Unique cookie associating related
events (for rename(2)) */
uint32_t len; /* Size of name field */
char name []; /* Optional null-terminated name */
};
wd: inotify_add_watch()返回的监视描述符
mask:包含发生事件的bit位
cookie:是连接相关事件的唯一整数。目前,这仅用于重命名事件,并允许应用程序连接生成的 IN_MOVED_FROM和IN_MOVED_TO事件对。对于所有其他事件类型,cookie设置为0。
len: name数组的长度
name: 发生事件的文件名的路径,每个路径以空格分割。
inotify event
可监视事件:
IN_ACCESS 以读方式访问文件
IN_ATTRIB 文件属性改变 举例: 权限,时间戳,扩展名,链接数,属主,属组的修改
IN_CLOSE_WRITE 关闭以写方式打开的文件
IN_CLOSE_NOWRITE 未写入的文件已关闭
IN_CREATE 在监视目录中创建文件或文件夹
IN_DELETE 在监视目录中删除文件或文件夹
IN_DELETE_SELF 被监视的文件/目录本身已被删除。
IN_MODIFY 文件已经修改
IN_MOVE_SELF 被监视的文件/目录本身已被移动。
IN_MOVED_FROM 文件移出监视目录
IN_MOVED_TO 文件移入监视目录
IN_OPEN 打开文件
IN_MOVE 等于IN_MOVED_FROM | IN_MOVED_TO
IN_CLOSE 等于IN_CLOSE_WRITE | IN_CLOSE_NOWRITE
内核限制
以下接口可用于限制inotify消耗的内核内存量:
/proc/SYS/FS/inotifyd/max_queued_events
inotify实例数上限,超出此限制的事件将被删除,但始终会生成IN_Q_OVERFLOW事件。
/proc/SYS/FS/inotifyd/max_user_instances
每个用户可以创建的inotify实例数的上限。
/proc/SYS/FS/inotifyd/max_user_watches
这指定了可以为每个真实用户创建的监视数量的上限。
编码
#include<stdio.h>
#include<stdlib.h>
#include<sys/inotify.h>
#define BUF_LEN 1000
void dealwithEvent(int fd_instan)
{
int readlen;
char buf[BUF_LEN] ={0};
char * p;
struct intofiy_event * event;
//读取事件,返回多个event结构体
readlen = read(fd_instan,buf, BUF_LEN);
if ( -1 == readlen )
{
printf("read failed errmsg = %s\n", strerror(errno));
exit(0);
}
for ( p =buf; p < buf+readlen;)
{
event = (struct inotify_event *)p;
if( event->mask & IN_CREATE)
{
printf("创建文件,filename = %s\n",event->name);
}
if( event->mask & IN_DELETE)
{
printf("删除文件,filename = %s\n",event->name);
}
p += sizeof(struct inotify_event) + event->len;
}
}
void do_select(int fd)
{
int ret;
fd_set rset;
struct timeval timeout;
while(1)
{
FD_ZERO(&rset);//每次循环背后,都需要重置
FD_SET(fd, &rset);
timeout.tv_sec = 5; //每次select后,都需要重置时间
timeout.tv_usec = 0;
//利用select 通知时间的发生
ret = select(fd+1, &rset,NULL,NULL,&timeout);
if( 0== ret)
{
printf(" Select timeout,continue\n");
continue;
}
else if(-1 == ret)
{
printf("select error,break\n");
break;
}
else
{
// fd可读
if (FD_ISSET(fd, &rset))
{
dealwithEvent(fd);
}
}
}
}
int main()
{
int fd_instan;
int wd;
fd_instan = inotify_init();
if ( -1 == fd_instan)
{
printf("init error\n");
return -1;
}
//添加监视点
wd = inotify_add_watch(fd, "/home/lxj/work/", IN_CREATE|IN_DELETE|IN_CLOSE_WRITE);
if (-1 == wd)
{
printf("inotify_add_watch error \n");
return -1;
close(fd_instan);
}
//利用select执行IO复用
do_select(fd_instal);
//删除监视,关闭inotify实例
inotify_rm_watch(fd_instan,wd);
close(fd_instan);
return 1;
}