Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use INotify to watch a file with multiple symlinks

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?

like image 263
Speed8ump Avatar asked Sep 28 '22 15:09

Speed8ump


1 Answers

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).

like image 187
tucuxi Avatar answered Oct 07 '22 19:10

tucuxi