You should not put i += EVENT_SIZE + event->len;
inside the if ( event->len )
block. If an event has a zero-length name, then the pointer should still be incremented by EVENT_SIZE
(which is what will happen if you put that statement outside the block). I think you might be seeing an infinite loop in your inotify program, kicked off by the first event which happens to have a zero-length name. (Which is exactly what happens with the ls
: The directory is being opened, not its files, so there's nothing in the name
field.)
inotify watcher stops working after ls or watch commands
سؤال
I took the code below from the many examples on the internet about how to use inotify.
I then tried the following experiment:
1) run the watcher below
2) in a separate shell, cd into '/mypath'
create some files to the folder you are watching. For example, 'date > output.txt'
one ore more times.
3) you will see notifications from the watcher.
4) type 'ls /mypath'
(or even 'watch -n 1 /mypath'
)
5) try 'date > output.txt'
in /mypath. You will no longer see notifications from the watcher. Or at least, this is what happened when I tested with Ubuntu 12/13.
Any ideas about how to fix it?
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <limits.h>
#include <unistd.h>
#define MAX_EVENTS 1024 /*Max. number of events to process at one go*/
#define LEN_NAME 16 /*Assuming that the length of the filename won't exceed 16 bytes*/
#define EVENT_SIZE ( sizeof (struct inotify_event) ) /*size of one event*/
#define BUF_LEN ( MAX_EVENTS * ( EVENT_SIZE + LEN_NAME )) /*buffer to store the data of events*/
int main()
{
int length, i = 0, wd;
int fd;
char buffer[BUF_LEN];
/* Initialize Inotify*/
fd = inotify_init();
if ( fd < 0 ) {
perror( "Couldn't initialize inotify");
}
/* add watch to starting directory */
wd = inotify_add_watch(fd, "/mypath", IN_CLOSE_WRITE | IN_CLOSE_NOWRITE);
if (wd == -1)
{
printf("Couldn't add watch to %s\n","/mypath");
}
else
{
printf("Watching:: %s\n","/mypath");
}
/* do it forever*/
while(1)
{
i = 0;
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_CLOSE_WRITE) {
if (event->mask & IN_ISDIR)
printf( "The directory %s was Created.\n", event->name );
else
printf( "The file %s was closed (write) with WD %d\n", event->name, event->wd );
}
if ( event->mask & IN_CLOSE_NOWRITE) {
if (event->mask & IN_ISDIR)
printf( "The directory %s was Created.\n", event->name );
else
printf( "The file %s was closed (nowrite) with WD %d\n", event->name, event->wd );
}
i += EVENT_SIZE + event->len;
}
}
}
/* Clean up*/
inotify_rm_watch( fd, wd );
close( fd );
return 0;
}
المحلول
نصائح أخرى
You get into an ever-ending loop since you do not change i
when event->len == 0
Add this:
else
i += EVENT_SIZE ;
in case if ( event->len == 0 )
It turns out that when your program stops working it eats all the CPU. I made a few changes and it seems to work now. Here are the details:
Declare BUF_LEN to handle 16 events (you can increase that value):
#define BUF_LEN (16 * (sizeof(struct inotify_event) + NAME_MAX + 1))
Change your while (i < length)
loop that processes the events to the following for loop:
for ( p = buffer; p < buffer + length; ) {
struct inotify_event *event = ( struct inotify_event * ) p;
p += sizeof(struct inotify_event) + event->len;
if ( event->len ) {
/* SNIP */
}
}
The p
variable should be declared as char *
and you can remove the i
which is not used anymore.