在linux下使用inotify监控,能不能够知道监控目录下子目录中是哪个文件被修改了。。。求方法。。。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在linux下使用inotify监控,能不能够知道监控目录下子目录中是哪个文件被修改了。。。求方法。。。相关的知识,希望对你有一定的参考价值。

现在只能通过event->mask & IN_ISDIR 知道子目录被修改了,具体里面哪个文件就没法得知了

这个我们期末考试考过。
inotify只能监控单层目录变化,不能监控子目录中的变化情况。
如果需要监控子目录,需要在调用inotify_add_watch(int fd, char *dir, int mask):int建立监控时,递归建立子目录的监控,伪代码如下
void addwatch(int fd, char *dir, int mask)

wd = inotify_add_watch(fd, dir, mask);
向目录集合加入(wd, dir);
for (dir下所有的子目录subdir)
addwatch(fd, subdir, mask);

这样就可以得到一个目录集合,其中每一个wd对应一个子目录。
当你调用read获取信息时,可以得到一个下面的结构体
struct inotify_event

int wd; /* Watch descriptor. */
uint32_t mask; /* Watch mask. */
uint32_t cookie; /* Cookie to synchronize two events. */
uint32_t len; /* Length (including NULs) of name. */
char name __flexarr; /* Name. */
;
其中,通过event->wd和刚才记录的目录集合可以知道变动的具体子目录。
event->name为具体的文件名称。
event->name是一个char name[0]形式的桩指针,具体的name占据的长度可以由event->len得出

我的监控部分代码如下:
enum EVENT_SIZE = sizeof(struct inotify_event);
enum BUF_SIZE = (EVENT_SIZE + 16) << 10;
void watch_mon(int fd)

int i, length;
void *buf;
struct inotify_event *event;
buf = malloc(BUF_SIZE);

while ((length = read(fd, buf, BUF_SIZE)) >= 0)

i = 0;
while (i < length)

event = buf + i;
if (event->len)
具体处理函数(event);
i += EVENT_SIZE + event->len;


close(fd);
exit(1);

在你的具体处理函数中,通过wd辨识子目录,通过name辨识文件

这是利用C++STLmap写的一个范例,可以监视当前目录下(含子目录)的变化,创建,删除过程(新建立的目录不能监视,只能通过监视到创建新目录的事件后重新初始化监视表)
新版1.1.0,可以监视创建的子目录,方法是,当do_action探测到新目录创建的动作时,调用inotify_add_watch追加新的监视
/*
Copyright (C) 2010-2011 LIU An (SuperHacker@china.com.cn)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <errno.h>
#include <dirent.h>

#include <map>
#include <string>
using namespace std;

void addwatch(int, char*, int);
static int filter_action(uint32_t mask);
int watch_init(int mask, char *root);
void addwatch(int fd, char *dir, int mask);
static void do_action(int fd, struct inotify_event *event);
void watch_mon(int fd);
static void send_mess(char *name, char *act, int ewd);
void append_dir(int fd, struct inotify_event *event, int mask);

map<int, string> dirset;

enumMASK = IN_MODIFY | IN_CREATE | IN_DELETE;

int main(int argc, char **argv)

int fd;
if (argc != 2)

fprintf(stderr, "Usage: %s dir\n", argv[0]);
exit(1);


fd = watch_init(MASK, argv[1]);
watch_mon(fd);

return 0;


int watch_init(int mask, char *root)

int i, fd;

if ((fd = inotify_init()) < 0)
perror("inotify_init");
addwatch(fd, root, mask);
return fd;


void addwatch(int fd, char *dir, int mask)

int wd;
char subdir[512];
DIR *odir;
struct dirent *dent;

if ((odir = opendir(dir)) == NULL)

perror("fail to open root dir");
exit(1);

wd = inotify_add_watch(fd, dir, mask);
dirset.insert(make_pair(wd, string(dir)));

errno = 0;
while ((dent = readdir(odir)) != NULL)

if (strcmp(dent->d_name, ".") == 0
|| strcmp(dent->d_name, "..") == 0)
continue;
if (dent->d_type == DT_DIR)

sprintf(subdir, "%s/%s", dir, dent->d_name);
addwatch(fd, subdir, mask);



if (errno != 0)

perror("fail to read dir");
exit(1);


closedir (odir);


enum EVENT_SIZE = sizeof(struct inotify_event);
enum BUF_SIZE = (EVENT_SIZE + 16) << 10;

void watch_mon(int fd)

int i, length;
void *buf;
struct inotify_event *event;
buf = malloc(BUF_SIZE);

while ((length = read(fd, buf, BUF_SIZE)) >= 0)

i = 0;
while (i < length)

event = (struct inotify_event*)(buf + i);
if (event->len)
do_action(fd, event);
i += EVENT_SIZE + event->len;


close(fd);
exit(1);


static char action[][10] =

"modified",
"accessed",
"created",
"removed"
;

enumNEWDIR = IN_CREATE | IN_ISDIR;

static void do_action(int fd, struct inotify_event *event)

int ia, i;

if ((ia = filter_action(event->mask)) < 0)
return;

if ((event->mask & NEWDIR) == NEWDIR)
append_dir(fd, event, MASK);

send_mess(event->name, action[ia], event->wd);


void append_dir(int fd, struct inotify_event *event, int mask)

char ndir[512];
int wd;

sprintf(ndir, "%s/%s", dirset.find(event->wd)->second.c_str(),
event->name);
wd = inotify_add_watch(fd, ndir, mask);
dirset.insert(make_pair(wd, string(ndir)));


static int filter_action(uint32_t mask)

if (mask & IN_MODIFY)
return 0;
if (mask & IN_ACCESS)
return 1;
if (mask & IN_CREATE)
return 2;
if (mask & IN_DELETE)
return 3;
return -1;


static void send_mess(char *name, char *act, int ewd)

char format[] = "%s was %s.\n";
char file[512];

sprintf(file, "%s/%s", dirset.find(ewd)->second.c_str(), name);

printf(format, file, act);


参考资料是我们作业的提交,没有考虑递归创建子目录监控的问题。

参考资料:http://59.67.33.217/homeworkref/sources/2010-2011-1.2008.software.os.inotify.tar.xz

参考技术A 你可以试试自己用 mingw 编译一个 DOS 下面可用的 tail 啊~

如果你用 windows 的 cmd 。可以看看 powershell 有没有这个命令。
或者尝试安装一个 cygwin ,里面我记得有这个命令。之后用 cywin 的 bash 命令行当命令行用。

你要是用纯 DOS ,貌似你可以放弃计算机了……

NFS+inotify实时同步

Inotify简介

Inotify是一种文件系统事件通告机制,能够实时监控文件系统下文件的访问、修改、删除等各种变化情况并将其作为事件通告给用户态应用程序。Linux内核从2.6.13版本后已经集成了Inotify的功能,用户只需安装inotify应用程序即可实现对文件系统的监控。

配置Rsync服务端

rpm -qa | grep rsync

vim /etc/rsyncd.conf

uid = rsync                         #客户端进行数据传输时所使用的用户
gid = rsync                         #客户端进行数据传输时所使用的用户组
user chroot = no                    #安全相关
max connections = 200               #最大连接数
timeout = 300                       #超时时间,客户端连接后300s不传输自动断开
pid file = /var/run/rsyncd.pid      #进程号文件
lock file = /var/run/rsync.lock     #锁文件
log file = /var/log/rsyncd.log      #日志文件  
ignore errors                       #忽略错误
read only = false                   #可写
list = false                        #客户端不能ls等进行列表
hosts allow = 172.16.1.0/24         #允许连接的主机
#hosts deny = 0.0.0.0/32            #拒绝的主机
auth users = rsync_backup           #客户端登录账号名
secrets file = /etc/rsync.password  #密码文件,用于验证
[backup]                            #模块名称
path = /backup/                     #提供访问的目录
[nfsbackup]
path = /nfsbackup

useradd rsync -s /sbin/nologin –M
mkdir /backup
chown rsync.rsync /backup
vim /etc/rsync.password

rsync_backup:peterwang

chmod 600 /etc/rsync.password
rsync --daemon
ps -ef | grep rsync | grep -v grep
lsof -i :873
echo "/usr/bin/rsync --daemon" >> /etc/rc.local 

 配置NFS服务端

wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo
yum install -y inotify-tools
vim /etc/rsync.password

peterwang

chmod 600 /etc/rsync.password
mkdir /server/scripts -p
cd /server/scripts
vim inotify.sh

#!/bin/bash
export PATH=/bin:/usr/bin:/usr/local/bin
SRC=/data
DEST=nfsbackup
IP=172.16.1.41
USER=rsync_backup
PASSFILE=/etc/rsync.password
inotifywait -mrq --format ‘%w%f‘ -e modify,create,move,delete,attrib $SRC | while read line
do
NUM=$(echo $line | grep -o "/" | wc -l)
if [ $NUM -gt 2 ];then
DIR=$(echo $line | awk -F "/" ‘{print "/"$2"/"$3}‘)
rsync -az $DIR --delete rsync://[email protected]$IP/$DEST --password-file=$PASSFILE
else
rsync -az $SRC/ --delete rsync://[email protected]$IP/$DEST --password-file=$PASSFILE
fi
done &

sh inotify.sh
echo "/bin/sh /server/scripts/inotify.sh " >> /etc/rc.local

 

以上是关于在linux下使用inotify监控,能不能够知道监控目录下子目录中是哪个文件被修改了。。。求方法。。。的主要内容,如果未能解决你的问题,请参考以下文章

Haskell:在不轮询的情况下监控文件(在 linux 中使用 inotify)

Inotify: 高效实时的Linux文件系统事件监控框架

使用 Perl 和 Linux::Inotify2 模块监控 Mac 地址的日志文件

NFS+inotify实时同步

Linux 文件操作监控inotify功能及实现原理

linux 实时同步inotify