Ayush choubey
Ayush choubey

Reputation: 616

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 );
}

Upvotes: 6

Views: 1839

Answers (2)

Wez Furlong
Wez Furlong

Reputation: 4987

For the blocking read call, see: https://stackoverflow.com/a/914520/149111

You may also want to switch from IN_CLOSE_WRITE to IN_ALL_EVENTS to make sure you're not missing something; likely a delete:

It is a best practice to watch the dir that contains the file(s) of interest rather than the individual files, as this will consume fewer resources in the kernel. It will also allow you to observe "atomic" file replacement operations where the writer creates a temporary file on the file system (perhaps in the same dir), write to the temporary file and then at the end rename(2) it over the top of the original file.

This style of replacement ensures that observers of the file will only ever notice the complete content of the file and not a half-written version of it.

Upvotes: 2

Ayush choubey
Ayush choubey

Reputation: 616

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

Upvotes: 4

Related Questions