Use INotify to watch a file with multiple symlinks

c, c++, inotify, linux, symlink

Solution

My answer is a straight "yes, you are doing it right".

After carefully reading the inotify syscall manpage, I cannot see any way of short of watching every step of a (possibly-symlinked) path-to-a-file in order to detect any and all changes to the full path.

This just seems to be the way `inotify` works: it only looks at specific files or folders, and it does not do recursion on its own. That, plus having to explicitly follow symlinks, seems to match your 3-step plan to the letter.

Selected quotes from the manpage:

The following further bits can be specified in mask when calling inotify_add_watch(2): IN_DONT_FOLLOW (since Linux 2.6.15)

Don't dereference pathname if it is a symbolic link.

[...]

Limitations and caveats

Inotify monitoring of directories is not recursive: to monitor subdirectories under a directory, additional watches must be created. This can take a significant amount time for large directory trees. [...]

This FAQ also lends support for your strategy re symlinks:

Q: What about the IN_ONLYDIR and IN_DONT_FOLLOW flags? IN_ONLYDIR ensures that the event occur only on a directory. If you create such watch on a file it will not emit events. IN_DONT_FOLLOW forbids following symbolic links (these ones will be monitored themselves and not the files they point to).

Problem

So I setup some code to watch a config file for edits, which worked until I used VIM to edit the file, then I had to also watch the directory for renames and creations. Then I discovered that didn't catch renames higher in the path hierarchy. Then I looked into symlinks...gaaahhhh! First setup a made up example showing one (of many) tricky symlink scenarios: ``` mkdir config1 touch config1/config ln -s config1 machine1 mkdir config2 touch config2/config ln -s config2 machine2 ln -s machine1 active ``` Now, given a filename like active/config that I want to watch, I can see how to get an inotify watch descriptor for: ``` config1/ -> watch active/ follow symlinks (watches inode for config1) active/ -> watch active/ dont follow symlinks (watches inode for active symlink active/config -> watch active/config (watches inode for config1/config) ``` How do I add a watch on the machine1 symlink? Do I need to find some way to manually walk each symlink adding watches for each along the way? How? The purpose is to allow: ``` mkdir config3 touch config3/config ln -s -f -n config3 machine1 ``` And have inotify warn that active/config has been redirected. At the moment it looks like I'll have to add a watch for: ``` - target file inode - every directory inode leading to the file (to detect moves/renames of directories) - every symlink inode involved in reaching any of the above ``` There must be an easier way to just watch one file? Have I strayed from the path or is this really the way?

Original source