通知丢失的事件
Posted
技术标签:
【中文标题】通知丢失的事件【英文标题】:inotify missing events 【发布时间】:2013-04-04 08:48:00 【问题描述】:我想监控我系统上的 USB 密钥。我知道它们总是挂载在 /media 中,所以我使用 inotify 来监控 /media。一些 USB 密钥在插入时会创建一个文件夹(例如 sda),该文件夹会一直保留到它们被拔出,有些则创建一个文件夹(例如 sda),立即删除它并创建一个新文件夹(例如 sda1)。这是由于键上的分区。
但是,有时 inotify 仅捕获创建和删除第一个文件夹的事件,而错过了第二个文件夹的创建。当我手动检查 /media 时,第二个文件夹存在,但从未被 inotify 通知。
这种情况很少发生,当它发生时,它总是在设备重启后的第一个插头处。
#include <sys/inotify.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
/* size of the event structure, not counting name */
#define EVENT_SIZE (sizeof (struct inotify_event))
/* reasonable guess as to size of 32 events */
#define BUF_LEN (32 * (EVENT_SIZE + 16))
int main(int argc, char **argv)
int fd,wd,len,i;
char buf[BUF_LEN];
struct inotify_event *event;
fd_set watch_set;
fd = inotify_init();
if (fd < 0)
perror("init failed");
exit(EXIT_FAILURE);
wd = inotify_add_watch(fd,"/media",IN_ALL_EVENTS);
if (wd < 0)
perror("add watch failed");
exit(EXIT_FAILURE);
/* put the file descriptor to the watch list for select() */
FD_ZERO(&watch_set);
FD_SET(fd,&watch_set);
while(1)
select(fd+1,&watch_set,NULL,NULL,NULL);
len = read(fd,buf,BUF_LEN);
i=0;
while(i < len)
event = (struct inotify_event *) &buf[i];
if ((event->mask & IN_CREATE) != 0)
printf ("%s created\n",event->name);
else if ((event->mask & IN_DELETE) != 0)
printf ("%s deleted\n",event->name);
else
printf ("wd=%d mask=0x%X cookie=%u len=%u name=%s\n",
event->wd, event->mask,
event->cookie, event->len, event->name);
i += EVENT_SIZE + event->len;
有什么想法吗?
【问题讨论】:
是否可以删除与***.com/questions/15350369/how-to-use-inotify-in-c 相关的/media
并创建一个新的/media
而没有为其创建新的inotify_add_watch
?
只创建和删除 /media 的子文件夹。虽然错过了一个事件,但下一个事件又被抓住了。所以手表还在运行。
【参考方案1】:
inotify 的子文件夹问题众所周知并且很容易重现:
启动 inotifywait 观察一个空的 tmp 目录:
inotifywait -e create -m -r --format '%:e %f' ./tmp
在另一个shell中输入:
mkdir tmp/0 tmp/0/0 tmp/0/0/0 tmp/0/0/0/0
您很可能只会收到第一个子目录的通知。
创建:ISDIR 0
在创建目录、您的应用程序收到通知以及添加新的 inotify 监视之间丢失事件(特别是子目录创建事件)的明显可能性,使得递归监控过于不可靠。唯一安全的选择是扫描新创建目录的内容。
来自限制和警告下的inotify doc:
如果监视整个目录子树,并且新的子目录是 在该树中创建,请注意,在您创建手表时 新的子目录,新文件可能已经在 子目录。因此,您可能需要扫描 添加手表后立即创建子目录。
【讨论】:
仔细看bad的问题,他只关心一个目录级别,所以上面的不适用。 但是,再深入一点,这可能不是坏人想要的:fd = inotify_init();如果使用 select,这应该是: fd = inotify_init1(IN_NONBLOCK);使用 select,立即接收子目录事件,而不是缓冲。 正如你所提到的,子目录并不是让我担心的,我只对一个目录级别的事件感兴趣。但是,同时我发现这是 inotify 的一个已知问题(请参阅我的回答)【参考方案2】:与此同时,我发现这是 inotify 的一个已知问题。如果两个事件几乎同时出现,则 inotify 只捕获其中一个。 我的解决方案:我不再使用inotify,而是使用libudev来监控插入机器的设备......
【讨论】:
这个问题在任何地方都有描述吗?【参考方案3】:您可以使用inotifywait
命令(来自inotify-tools
包)监视/media 目录,以检查您感兴趣的inotify
事件是否发生.
参考:http://www.noah.org/wiki/Inotify,_FAM,_Gamin#Examples_with_inotify-tools
如果inotify
确实错过了事件,原因可能是:Inotify
确实报告了sysfs
和procfs
中的部分但不是全部事件。
(嗯,我不能肯定。只是我的猜测。)
参考:http://en.wikipedia.org/wiki/Inotify#Limitationshttp://en.wikipedia.org/wiki/Sysfshttp://en.wikipedia.org/wiki/Procfs
【讨论】:
以上是关于通知丢失的事件的主要内容,如果未能解决你的问题,请参考以下文章