The Filesystem notification APIs allows applications to watch certain files and be notified when they are opened, modified, deleted, or renamed. This greatly aids the applications, because before such filesystem event monitoring tools existed, such applications would have to read the disk repeatedly to detect any changes, which resulted in high disk and CPU usage.
File system event monitoring tools
There are few tools to do the job, namely:
- FAM (File Alteration Monitor) – It is one of the oldest portable event monitors. It sends events to an application when changes are made to files or directories that an application has registered to be monitored. It is also complicated.
- Gamin – newer and simpler than
FAM
. It tries to be compatible with FAM while not implementing many of the obscure feature. It is moderately maintained and widely available on many distros. It is portable, but the focus of development and testing is on Linux. It has BSD support and can be found in FreeBSD Ports. - dnotify – introduced in 2.4 kernel series. It can only watch directories and requires maintaining an open file descriptor to the directory that the user wants to watch. It has been obsoleted by
inotify
. - inotify – a
dnotify
replacement. It’s part of the Linux kernel subsystem and included in mainline Linux kernel since release 2.6.13. It’s fast and lightweight and should be available under all Linux distributions.
Installation and Examples
In this article, we will use inotify
(inode notify) to detect file system changes. Let’s begin by first installing the inotify-tools
package. The package includes a set of command-line programs that provide a simple interface to inotify
. The libnotify-bin
package is optional and is only needed for GUI desktop notifications.
On Ubuntu or Debian:
1 |
$ sudo apt-get install inotify-tools libnotify-bin |
On RedHat, Fedora or CentOS:
1 |
# yum install inotify-tools libnotify-bin |
There are a handful of events that can be monitored. They are
- access – A watched file or a file within a watched directory was read from.
- modify – A watched file or a file within a watched directory was written to.
- attrib – The metadata of a watched file or a file within a watched directory was modified. This includes timeāstamps, file permissions, extended attributes etc.
- close_write – A watched file or a file within a watched directory was closed, after being opened in writeable mode. This does not necessarily imply the file was written to.
- close_nowrite – A watched file or a file within a watched directory was closed, after being opened in read-only mode.
- close – A watched file or a file within a watched directory was closed, regardless of how it was opened. Note that this is actually implemented simply by listening for both close_write and close_nowrite, hence all close events received will be output as one of these, not CLOSE.
- open – A watched file or a file within a watched directory was opened.
- moved_to – A file or directory was moved into a watched directory. This event occurs even if the file is simply moved from and to the same directory.
- moved_from – A file or directory was moved from a watched directory. This event occurs even if the file is simply moved from and to the same directory.
- move – A file or directory was moved from or to a watched directory. Note that this is actually implemented simply by listening for both moved_to and moved_from, hence all close events received will be output as one or both of these, not MOVE.
- move_self – A watched file or directory was moved. After this event, the file or directory is no longer being watched.
- create – A file or directory was created within a watched directory.
- delete – A file or directory within a watched directory was deleted.
- delete_self A watched file or directory was deleted. After this event the file or directory is no longer being watched. Note that this event can occur even if it is not explicitly being listened for.
- unmount – The filesystem on which a watched file or directory resides was unmounted. After this event the file or directory is no longer being watched. Note that this event can occur even if it is not explicitly being listened to.
Let’s say you want to monitor a file $HOME/foo
for changes, run inotifywait
and wait for the “modify
” event type to occur.
1 |
$ inotifywait -e modify $HOME/foo |
The inotifywait
command will block (or will not terminate) till the file is modified. File read operations will not be monitored since we only requested for modify
events.
If you need to get statistics on file system changes, inotifywatch
is the command to be used. To monitor how often the $HOME/foo
file is being modified during a 1 minute interval, use the following syntax. After 60 seconds, you will get a summary output.
1 2 3 4 5 |
$ inotifywatch -e modify -t 60 $HOME/foo Establishing watches... Finished establishing watches, now collecting statistics. total modify filename 10 10 /home/ibrahim/foo |
You can also monitor a directory for changes. For example, to detect USB events (e.g a USB device that has been plugged in), we could just monitor the /dev
directory. After you plug in a USB device to the USB port, the Linux kernel will add a new block device in the /dev
directory. The below command will continously notify you of events within the /dev
directory.
1 |
$ inotifywait -mr -e create -e delete /dev |
To send a desktop notification on X-Windows or X11, the notify-send
command has to be used. notify-send
is part of the libnotify-bin
package. To monitor a file continuously and send desktop notifications whenever a change is detected, use a loop similar to the one below.
1 2 |
$ inotifywait -mrq -e create -e modify -e delete $HOME/foo | \ while read file; do (notify-send "File udated: $file"&) done |
The above loop could also be used in a shell script to continuously perform an action whenever a file system change is detected.