12

I am trying to run an example of inotify in C..but it's not working. I want to monitor modifications to a file (the file is tmp.cfg), but it doesn't work..I don't know if i'm running it correctly, because I understand how to monitor directories, but not a single file Here´s the example:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <unistd.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];

  fd = inotify_init();

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

  wd = inotify_add_watch( fd, "/home/name/tmp.cfg",
                         IN_MODIFY | IN_CREATE | IN_DELETE );
  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->mask & IN_CREATE ) {
          printf( "The file %s was created.\n", event->name );
      }
      else if ( event->mask & IN_DELETE ) {
          printf( "The file %s was deleted.\n", event->name );
      }
      else if ( event->mask & IN_MODIFY ) {
          printf( "The file %s was modified.\n", event->name );
      }
    i += EVENT_SIZE + event->len;
  }

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

  return 0;
}

Once i run it, if i write something on the file and then save it, nothing happens. i've tryed debugging it..the problem seems to be the if ( event->mask & IN_MODIFY ), as it doesn't recognize it as a modification

mar_sanbas
  • 833
  • 2
  • 12
  • 20
  • 1
    Just curious: why are you casting the return values from inotify_rm_watch() and close() to void? – senfo Sep 28 '20 at 19:26

4 Answers4

9

You have 2 issues. First, as far as I can tell, inotify does not really work on files - it needs directory name to watch.

Second, you missed if (event->len) { inside while loop.

This code works for me for creating, deleting and modifying files in current directory:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <unistd.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];

    fd = inotify_init();

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

    wd = inotify_add_watch(fd, ".",
        IN_MODIFY | IN_CREATE | IN_DELETE);
    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_CREATE) {
                printf("The file %s was created.\n", event->name);
            } else if (event->mask & IN_DELETE) {
                printf("The file %s was deleted.\n", event->name);
            } else if (event->mask & IN_MODIFY) {
                printf("The file %s was modified.\n", event->name);
            }
        }
        i += EVENT_SIZE + event->len;
    }

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

    return 0;
}
mvp
  • 111,019
  • 13
  • 122
  • 148
  • You may be right. However, if I use file name, change notification does not seem to work for me – mvp Nov 13 '12 at 06:20
  • the `name` shouldn't be printed too because that's only there when a file in watched directory changes. – iabdalkader Nov 13 '12 at 06:22
  • Ah, I see. But it only works if file already existed. Seems like watching directory and comparing for file name is more robust (but could be slow if other files change) – mvp Nov 13 '12 at 06:25
  • yes the file must be there first, because the watch is added on the file. – iabdalkader Nov 13 '12 at 06:30
  • 1
    For some reason it doesn't work with files..i don't know why, because when i try inotify for directories it works fine. – mar_sanbas Nov 15 '12 at 17:17
  • I've tryed changin the IN_MODIFY for IN_CLOSE_WRITE, and now it works! But i'm trying to do an infinite loop, so that it keeps reporting. Now the problem is that it detects the first modification, but not the following ones – mar_sanbas Nov 15 '12 at 18:50
  • it is only working only once. Could we get list of files creations. – GNK Feb 02 '21 at 14:55
5

It doesn't work on a single file because, when we use a editor to modify file, the editor opens a copy of the file and when we save the edited version from the text editor, the existing file is deleted and a new file of the same name is created with the modifications.

When the old file is deleted, the watch created on that file becomes invalid and it is deleted automatically.

You can see the old file being replaced by the new file if you monitor the parent directory.

There are two ways to solve it, monitor the parent directory and print the message when modifications is done to the particular that you want to watch.

Else create a new watch on the file whenever modifications are made. When the old file is deleted, IN_DELETE_SELF event is triggered.

event->name will be non-empty only when you watch a directory, as it will contain the name of the file on which the event has occurred in the watched directory.

jibin mathew
  • 682
  • 11
  • 14
1

I think you're not using your user name, which is your home directory, and you're not checking the return of inotify_add_watch which probably fails:

"/home/name/tmp.cfg"

Edit: okay second problem, you shouldn't print name because

The name field is only present when an event is returned for a file inside a watched directory;

Edit2: third problem, the file must exist before you run the program because you add a watch on the file, I suggest you check the error from inotify_add_watch

iabdalkader
  • 17,009
  • 4
  • 47
  • 74
1

In watching a file, if the file is manipulated by an editor which you might do to edit it and create a change, it is likely to be doing some operations that results in the original file you asked to watch being deleted. Hence the notifications will stop if you only watch the one file.

madGambol
  • 15
  • 2