Search code examples
cfile-descriptorinotifyposix-select

inotify api stops working after reporting once or twice


I wanted to test inotify, so took a couple of examples from internet, modified it to learn various aspects, but failed as it didn't work like i wanted to. First i tried to watch over a directory where it worked pretty nicely.

So i extended that example for file with some modification, but it works for one time only and gets blocked on read function

#include <sys/inotify.h>
#include <unistd.h>
#include <stdio.h>

#define EVENT_SIZE  (sizeof (struct inotify_event))
#define BUF_LEN        (16 * (EVENT_SIZE + 16))

int main()
{
    int fd;
    fd = inotify_init();
    if (fd < 0)
        perror("inotify_init()");
        int wd;
        wd = inotify_add_watch(fd, "target", IN_CLOSE_WRITE);
    if (wd < 0)
        perror("inotify_add_watch");

    char buf[BUF_LEN];
    int len;

    while(1) {

         len = read(fd, buf, BUF_LEN);

         printf("after read\n");

        if (len > 0)
        {
            int i = 0;
            while (i < len)
            {
                struct inotify_event *event;
                event = (struct inotify_event *) &buf[i];

                printf("wd=%d mask=%x cookie=%u len=%u\n",
                    event->wd, event->mask,
                    event->cookie, event->len);

                if (event->mask & IN_MODIFY)
                printf("file modified %s", event->name);

                if (event->len)
                printf("name=%s\n", event->name);

                i += EVENT_SIZE + event->len;
             }
        }

    }

    return 0;
}

So, i shifted to select(), but here also, it works once,reports twice then stop reporting the changes.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>

#define EVENT_SIZE  ( sizeof (struct inotify_event) )
#define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )

int main( int argc, char **argv ) 
{
int length, i = 0;
int fd;
int wd;
char buffer[BUF_LEN];

struct timeval timeout;

fd = inotify_init();

if ( fd < 0 ) {
   perror( "inotify_init" );
}

wd = inotify_add_watch( fd, "target", 
                      IN_CLOSE_WRITE );
fd_set rfds,rfdss;
int ret;

/* zero-out the fd_set */
FD_ZERO (&rfds);
FD_ZERO (&rfdss);
FD_SET (fd, &rfds);

timeout.tv_sec = 5;    
timeout.tv_usec = 0;

while(1){
    printf("Before select\n");
    //rfds = rfdss;
    ret = select (fd + 1, &rfds, NULL, NULL, NULL);
    printf("After Select\n");
    timeout.tv_sec = 5;     
    timeout.tv_usec = 0; 
    if (ret < 0)
            perror ("select");
    else if (!ret){
    }
            /* timed out! */
    else if (FD_ISSET (fd, &rfds)){
            printf("file changed============\n");
            length = read( fd, buffer, BUF_LEN );
    }
}

  ( void ) inotify_rm_watch( fd, wd );
 ( void ) close( fd );

 exit( 0 );
}

Solution

  • A bit of research showed that that the popular editors save it in different way.

    Instead of overwriting that file directly, they actually make a temporary file and then replace original file with new temporary one. So what actually happens is the file which you were actually watching no longer exists and therefore any changes that would be making won't be reflected back.

    Editors that actually follow this method are(many more may exist) Gedit, Geany, vi

    Editors that directly overwrite the file is(many more may exist) nano

    Hence even though code was correct, anomalous behavior of editor can be problematic