Linux下Inotify的学习和使用


=Start=

缘由:

在Linux下需要监控某个文件/目录的变化并进行通知,常用的「tail -f」可以对文件内容进行监控,但是对于目录一级的监控它就没什么办法了。之前有了解过Linux的Inotify机制,这次趁着机会重新学习一下,并整理一些常见脚本方便日常使用、参考。

正文:
0x01.Inotify是什么?

Inotify是一种强大的、细粒度的、异步的文件系统事件监控机制Linux内核从2.6.13开始引入,允许监控程序打开一个独立文件描述符,并针对事件集监控一个或者多个文件,例如打开、关闭、移动/重命名、删除、创建或者改变属性。

0x02.我的系统是否支持Inotify机制?

方法一:判断你的Linux内核是否支持Inotify机制可以通过执行下面这条命令:

$ grep INOTIFY_USER /boot/config-$(uname -r)

如果输出「CONFIG_INOTIFY_USER=y」,就表示你的内核支持Inotify机制。

方法二:还可以使用「ll /proc/sys/fs/inotify」命令,是否有以下三条信息输出,如果没有表示不支持。

-rw-r--r-- 1 root root 0 5月 31 11:23 max_queued_events
-rw-r--r-- 1 root root 0 5月 31 11:23 max_user_instances
-rw-r--r-- 1 root root 0 5月 31 11:23 max_user_watches
  • /proc/sys/fs/inotify/max_queued_evnets 表示调用inotify_init时分配给inotify instance中可排队的event的数目的最大值,超出这个值的事件被丢弃,但会触发IN_Q_OVERFLOW事件。
  • /proc/sys/fs/inotify/max_user_instances 表示每一个real user ID可创建的inotify instatnces的数量上限。
  • /proc/sys/fs/inotify/max_user_watches 表示每个inotify instatnces可监控的最大目录数量。如果监控的文件数目巨大,需要根据情况,适当增加此值的大小。

另:GNU的coreutils从7.5版本开始也支持Inotify了,我们可以运行下面的命令来确认:

#查看系统上coreutils的版本信息:
# yum info coreutils

#验证coreutils是否使用了Inotify机制
# strace -e inotify_init,inotify_add_watch tail -f /var/log/dmesg
...
inotify_init() = 4
inotify_add_watch(4, "/var/log/dmesg", IN_MODIFY|IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF) = 1
...

从现在开始,通过轮询来确认文件是否需要重新读取的方法应该作为古董了。

0x03.如何安装inotify-tools?

需要说明的是:Inotify是一种异步的文件系统事件监控机制,而非具体的工具。如果希望在Linux系统上利用该机制进行文件/目录的监控的话,可以使用inotify-tools。inotify-tools是用 C语言 实现的和Inotify接口进行交互的 库和工具集,现在最新版的inotify-tools是2010.3.7日发布的3.14版。你可以手动从源码编译安装,也可以使用Linux系统自带的包管理工具进行安装。下面以CentOS 6.5为例说明Inotify的安装过程(推荐使用yum进行安装):

$ yum search inotify-tools
$ yum info inotify-tools
$ sudo yum install inotify-tools

#或

$ wget http://github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz
$ tar zxf inotify-tools-3.14.tar.gz
$ cd inotify-tools-3.14/
$ ./configure --prefix=/usr && make && su -c 'make install'
0x04.使用Inotify时的注意事项?

使用Inotify时,要特别注意内核中关于它的两个配置。首先「/proc/sys/fs/inotify/max_user_instances」规定了每个用户所能创建的Inotify实例的上限;其次「/proc/sys/fs/inotify/max_user_watches」规定了每个Inotify实例最多能关联几个监控(watch)。你可以很容易地试验在运行过程中达到上限,如:

# inotifywait -r /
Setting up watches. Beware: since -r was given, this may take a while!
Failed to watch /; upper limit on inotify watches reached!
Please increase the amount of inotify watches allowed per user via `/proc/sys/fs/inotify/max_user_watches'.

如果要改变这些配置,只要向相应的文件写入新值即可,如下所示:

# cat /proc/sys/fs/inotify/max_user_watches
8192
# echo 16000 > /proc/sys/fs/inotify/max_user_watches
# cat /proc/sys/fs/inotify/max_user_watches
16000
0x05.Inotify使用示例
inotifywait的常用参数:

--timefmt 时间格式
    %y年 %m月 %d日 %H小时 %M分钟
--format 输出格式
    %T时间 %w路径 %f文件名 %e状态

-m 始终保持监听状态,默认触发事件即退出
-r 递归查询目录
-q 减少不必要的输出(只打印事件信息)

-e 定义监控的事件,可用参数:
    open   打开文件
    access 访问文件
    modify 修改文件
    delete 删除文件
    create 新建文件
    attrib 属性变更

--exclude <pattern> 指定要排除监控的文件/目录
#!/bin/bash

MONITOR_DIR="/tmp/src"

# inotifywait -mr --timefmt '%d/%m/%y %H:%M' --format '%T %w %f' -e close_write,modify,delete,create,attrib $MONITOR_DIR | while read DATE TIME DIR FILE; do

# inotifywait -mr -e close_write,modify,delete,create,attrib $MONITOR_DIR | while read path action file; do
# inotifywait -mr --format '%w %e %f' -e close_write,modify,delete,create,attrib $MONITOR_DIR | while read path action file; do

# inotifywait -mr --timefmt '%F_%T' --format '%w %e %f %T' -e close_write,modify,delete,create,attrib $MONITOR_DIR | while read path action file datetime; do
# inotifywait --exclude '^/tmp/src/mail/(large|ignore)/' -mr --timefmt '%F_%T' --format '%w %e %f %T' -e close_write,modify,delete,create,attrib $MONITOR_DIR | while read path action file datetime; do
# inotifywait --exclude '(.*/*\.log|.*/*\.swp)$|^/tmp/src/mail/(2014|201.*/cache.*)' -mr --timefmt '%F_%T' --format '%w %e %f %T' -e close_write,modify,delete,create,attrib $MONITOR_DIR | while read path action file datetime; do
# inotifywait --exclude '(.*/*\.log|.*/*\.swp)$' --fromfile rule.list -mr --timefmt '%F_%T' --format '%w %e %f %T' -e close_write,modify,delete,create,attrib $MONITOR_DIR | while read path action file datetime; do
while read path action file datetime; do

    echo "The file '$file' appeared in directory '$path' via '$action' @ '$datetime'"
    # FILECHANGE=${DIR}${FILE}
    # echo "At ${TIME} on ${DATE}, file $FILECHANGE was backed up via rsync"

done < <(inotifywait --exclude '(.*/*\.log|.*/*\.swp)$' --fromfile rule.list -mr --timefmt '%F_%T' --format '%w %e %f %T' -e close_write,modify,delete,create,attrib $MONITOR_DIR)
注意,上面的while循环,不要使用 $() 来包裹 inotifywait 命令,而要使用 <() ,具体原因参考:http://unix.stackexchange.com/questions/140679/using-inotify-to-monitor-a-directory-but-not-working-100 。

inotifywait排除监控目录有 `--exclude <pattern>` 和 `--fromfile <file>` 两种格式,并且可以同时使用,但前者可以用正则,而后者只能是具体的目录或文件。

$ vi ./rule.list
/tmp/src/pdf
@/tmp/src/2014

使用fromfile格式只能用绝对路径,不能使用诸如*正则表达式去匹配,@表示排除。

如果要排除的格式比较复杂,必须使用正则,那只能在inotifywait中加入选项,如 `--exclude '(.*/*\.log|.*/*\.swp)$|^/tmp/src/mail/(2014|201.*/cache.*)'` ,表示排除/tmp/src/mail/下的2014目录,和所有201*目录下的带cache的文件或目录,以及/tmp/src目录下所有的以.log或.swp结尾的文件。
参考链接:
=官方Wiki=
=使用说明/示例=

=END=


《 “Linux下Inotify的学习和使用” 》 有 9 条评论

  1. 有用的systemtap脚本集合(useful systemtap script)
    https://github.com/soarpenguin/systemtap-script

    内核调试神器SystemTap — 简介与使用(一)
    http://blog.csdn.net/zhangskd/article/details/25708441

    systemtap初体验
    https://phpor.net/blog/post/3471

    Linux 自检和 SystemTap
    https://www.ibm.com/developerworks/cn/linux/l-systemtap/
    http://blog.sae.sina.com.cn/archives/1488

    SystemTap Beginners Guide
    https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html-single/SystemTap_Beginners_Guide/

    http://blog.yufeng.info/archives/tag/systemtap

    Linux 下的一个全新的性能测量和调式诊断工具 Systemtap,第 1 部分: kprobe
    https://www.ibm.com/developerworks/cn/linux/l-cn-systemtap1/index.html

    RHEL 7特性说明(七):编译程序及工具
    https://linux.cn/article-3391-1.html

  2. 实时精准侦测站点目录中的各类 webshell
    https://klionsec.github.io/2017/12/25/modify-webshell/
    https://paper.tuisec.win/detail/7aecc20ba87c234
    `
    #!/bin/bash

    webshell_log=”/var/log/webshell.log”
    upload_shell=”/var/log/modify.tmp”
    # 只要一检测到有新事件发生就立马打包上传检测
    [ -s $webshell_log ] &&{
    awk -F ” ” ‘{print $3}’ $webshell_log |grep -E “.php$”| sort -u > $upload_shell
    cat $upload_shell |xargs zip ./maybeshell.zip
    echo $(curl https://scanner.baidu.com/enqueue -F [email protected]) | mail -s “webshell detect url api” [email protected]
    sleep 5
    > $webshell_log && > $upload_shell && rm -fr ./maybeshell.zip
    }
    `

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注