C++ – inotify watcher stops working after ls or watch commands

inotify watcher stops working after ls or watch commands… here is a solution to the problem.

inotify watcher stops working after ls or watch commands

I got the following code from many examples on how to use inotify on the internet.

Then I tried the following experiment:
1) Run the watcher
below
2) In a separate shell, cd into ‘/mypath' to create some files in the folder you are watching. For example, ‘date > output.txt' one or more times.
3) You will see notifications from observers.
4) Enter ‘ls/mypath’ (or even ‘watch -n 1/mypath').

5) Try ‘date > output.txt' in /mypath. You will no longer see notifications from observers. Or at least, this is what happened when I tested on Ubuntu 12/13.

Any ideas on 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;
}

Solution

You should not put i += EVENT_SIZE + event->len; Put in an if (event->len ) block. If the name length of the event is zero, the pointer should still be incremented by EVENT_SIZE (which happens if the statement is placed outside the block). I think you might see an infinite loop in the inotify program that is started by the first event that happens to have a zero-length name. (That’s exactly what happens with ls: the directory is being opened, not its files, so there’s nothing in the name field.) )

Related Problems and Solutions