Thread: Inotify problem

  1. #1
    Registered User
    Join Date
    Nov 2008
    Posts
    75

    Inotify problem

    I wrote this little example program just to start using inotify. The program adds a watch on a file, looking for the event of closing the file after having opened it for writing. When the even fires, I remove the watch, write something different on the file which the event was fired for and then I add again the watch on the same event on that file. All this in a cycle. The problem is that when I do any kind of writes on the file, even simple ones like this "echo 0 > file_watched", the watching program receives an unending series of events. What am I doing wrong?

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/inotify.h>
    
    #define FILE_CONTENTS "\
    irrelevant contents\n"
    
    #define EVENT_SIZE  (sizeof(struct inotify_event))
    
    int main(int argc, char **argv)
    {
    	if (argc < 2) {
    		printf("not enough arguments.\n");
    		exit(1);
    	}
    	char event[EVENT_SIZE];
    	int wd;
    	char *path_name = argv[1];
    	int ifd = inotify_init();
    	if (ifd == -1) {
    		printf("inotify_init() problem.\n");
    		exit(1);
    	}
    
    	while (true) {
    		wd = inotify_add_watch(ifd, path_name, IN_CLOSE_WRITE);
    		if (wd == -1) {
    			printf("inotify_add_watch() problem.\n");
    			exit(1);
    		}
    		if (read(ifd, event, EVENT_SIZE) != EVENT_SIZE) {
    			printf("read() problem.\n");
    			exit(1);
    		}
    		if(inotify_rm_watch(ifd, wd) == -1) {
    			perror("inotify_rm_watch()");
    			exit(1);
    		}
    		printf("%s modified. now working on it\n", path_name);
    		fflush(stdout);
    		FILE *file = fopen(path_name, "w");
    		fprintf(file, "%s", FILE_CONTENTS);
    		fflush(file);
    		fclose(file);
    		printf("%s restored\n", path_name);
    		fflush(stdout);
    	}
    	return (EXIT_SUCCESS);
    }

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Are you sure that your own program isn't affecting the watch by writing to the file?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    Nov 2008
    Posts
    75
    Quote Originally Posted by matsp View Post
    Are you sure that your own program isn't affecting the watch by writing to the file?

    --
    Mats
    I remove the watch before writing to the file.

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by MisterIO View Post
    I remove the watch before writing to the file.
    Yes, but are you then re-enabling the watch before or after the OS has actually finished updating the file?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Nov 2008
    Posts
    75
    Quote Originally Posted by matsp View Post
    Yes, but are you then re-enabling the watch before or after the OS has actually finished updating the file?

    --
    Mats
    Well, if you look at the code, you can see that I do a fflush(quite useless here) and a fclose on the file before the next cycle starts with the inotify_add_watch. With that code, if the kernel doesn't close the file before adding again the watch, wouldn't that be a kernel bug?

    Well, I may try to use only open and write, without using the std libc functions and see if it's a libc problem. But my first guess was that I did something wrong, being the first time I'm using inotify.

    No, I tried that, but it's the same if I use just open, write and close.
    Last edited by MisterIO; 11-14-2008 at 05:37 AM.

  6. #6
    Registered User
    Join Date
    Nov 2008
    Posts
    75
    Through debugging I noticed that the first time the watch legitimately fires the value of "mask" inside the struct inotify_event returned by the read is 0x8, which is the right value for IN_CLOSE_WRITE, as you can see in the kernel source file include/linux/inotify.h. Instead the following events read have a strange 0x32768 into the "mask" field, which, looking at that kernel source file, doesn't seem a legal value.
    Last edited by MisterIO; 11-14-2008 at 08:23 AM.

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by MisterIO View Post
    Through debugging I noticed that the first time the watch legitimately fires the value of "mask" inside the struct inotify_event returned by the read is 0x8, which is the right value for IN_CLOSE_WRITE, as you can see in the kernel source file include/linux/inotify.h. Instead the following events read have a strange 0x32768 into the "mask" field,, which, looking at that kernel source file, doesn't seem a legal value.
    0x32768 or 32768 decimal (0x8000 - IN_IGNORED)?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    Registered User
    Join Date
    Nov 2008
    Posts
    75
    Quote Originally Posted by matsp View Post
    0x32768 or 32768 decimal (0x8000 - IN_IGNORED)?

    --
    Mats
    You may be right. I thought the debugger gave the result as an hexadecimal number, because in the first case the values were equal, but it was 8, which is obviously the same both as a decimal and hexadecimal number.
    The manual says : IN_IGNORED -> Watch was removed explicitly (ino‐
    tify_rm_watch(2)) or automatically (file was
    deleted, or file system was unmounted).
    So this means that once I remove the watch, I can't expect the read call to block, because it actually returns an IN_IGNORED event? Isn't there any way to set the file descriptor back to its previous condition, that is receiving only IN_CLOSE_WRITE events? Otherwise I should control everytime the type of events returned, but this seems a bit retarded, having requested to receive _only_ one kind of events.

    EDIT : Yet this still doesn't explain all those events which I receive, nor why do I receive them.
    Last edited by MisterIO; 11-14-2008 at 09:32 AM.

  9. #9
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I have no idea - Maybe, for the way that you use it, you want use the IN_ONESHOT modifier?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  10. #10
    Registered User
    Join Date
    Nov 2008
    Posts
    75
    I've just tried to comment the part of the code where I write new values to the file, after having removed the watch, but it doesn't change anything, I still receive all those events.

    Edit : I wasn't answering to your last post. Now I'm looking into that.

  11. #11
    Registered User
    Join Date
    Nov 2008
    Posts
    75
    Quote Originally Posted by matsp View Post
    I have no idea - Maybe, for the way that you use it, you want use the IN_ONESHOT modifier?

    --
    Mats
    Yes, that solves the problem. It's not entirely clear why do I need it, because it actually should do what I was doing by hand, that is it removes the watch. As a consequence now clearly I don't need to use inotify_rm_watch and if I use it, it returns an error. To understand that, I should probably go looking into kernel code, but it seems at least a strange behaviour.

    P.S. Thanks a lot for the help!

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    When looking at this problem I found quite a few hits on "inotify example" - perhaps such a search and a read of the links that comes up would help. Reading kernel code is all well and good, but often examples will show more useful hints than trying to find why you are doing something wrong from reading the kernel code (I'm not saying for sure that you are doing anything wrong, but I would expect that the API itself isn't completely b0rked).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User
    Join Date
    Nov 2008
    Posts
    75
    Quote Originally Posted by matsp View Post
    When looking at this problem I found quite a few hits on "inotify example" - perhaps such a search and a read of the links that comes up would help. Reading kernel code is all well and good, but often examples will show more useful hints than trying to find why you are doing something wrong from reading the kernel code (I'm not saying for sure that you are doing anything wrong, but I would expect that the API itself isn't completely b0rked).

    --
    Mats
    Yeah, I looked at many examples on the net, but I didn't find one which resembled my case. Instead, searching for a solution, I found this interesting site, so I scored bigger than if I had found a good example.

  14. #14
    Registered User
    Join Date
    Nov 2008
    Posts
    75
    This is the working version of the code :
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <errno.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/inotify.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #define FILE_CONTENTS "\
    irrelevant contents\n"
    
    int main(int argc, char **argv)
    {
    	if (argc < 2) {
    		printf("not enough arguments.\n");
    		exit(1);
    	}
    	struct inotify_event event;
    	int wd;
    	char *path_name = argv[1];
    	int ifd = inotify_init();
    	if (ifd == -1) {
    		printf("inotify_init() problem.\n");
    		exit(1);
    	}
    
    	while (true) {
    		wd = inotify_add_watch(ifd, path_name, IN_CLOSE_WRITE | IN_ONESHOT);
    		if (wd == -1) {
    			printf("inotify_add_watch() problem.\n");
    			exit(1);
    		}
    		if (read(ifd, &event, sizeof(event)) != sizeof(event)) {
    			printf("read() problem.\n");
    			exit(1);
    		}
    		printf("&#37;s modified. now working on it\n", path_name);
    		fflush(stdout);
    		int fd = open(path_name, O_WRONLY);
    		write(fd, FILE_CONTENTS, strlen(FILE_CONTENTS));
    		close(fd);
    		printf("%s restored\n", path_name);
    		fflush(stdout);
    	}
    	return (EXIT_SUCCESS);
    }
    Many calls don't have proper error checks, but it's just an exercise.

  15. #15
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Have you TRIED using it without oneshot and just putting a bit of delay after you've written the file - I'm not suggesting that as a solution, just to get an idea of if a new watch very soon after the file changes is actually what happens or not.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Memory problem with Borland C 3.1
    By AZ1699 in forum C Programming
    Replies: 16
    Last Post: 11-16-2007, 11:22 AM
  2. Someone having same problem with Code Block?
    By ofayto in forum C++ Programming
    Replies: 1
    Last Post: 07-12-2007, 08:38 AM
  3. A question related to strcmp
    By meili100 in forum C++ Programming
    Replies: 6
    Last Post: 07-07-2007, 02:51 PM
  4. WS_POPUP, continuation of old problem
    By blurrymadness in forum Windows Programming
    Replies: 1
    Last Post: 04-20-2007, 06:54 PM
  5. beginner problem
    By The_Nymph in forum C Programming
    Replies: 4
    Last Post: 03-05-2002, 05:46 PM