Inotify file descriptors can be monitored using select(2),
poll(2), and epoll(7). When an event is available, the file
descriptor indicates as readable.
Since Linux 2.6.25, signal-driven I/O notification is available
for inotify file descriptors; see the discussion of F_SETFL
(for
setting the O_ASYNC
flag), F_SETOWN
, and F_SETSIG
in fcntl(2).
The siginfo_t structure (described in sigaction(2)) that is
passed to the signal handler has the following fields set: si_fd
is set to the inotify file descriptor number; si_signo is set to
the signal number; si_code is set to POLL_IN
; and POLLIN
is set
in si_band.
If successive output inotify events produced on the inotify file
descriptor are identical (same wd, mask, cookie, and name), then
they are coalesced into a single event if the older event has not
yet been read (but see BUGS). This reduces the amount of kernel
memory required for the event queue, but also means that an
application can't use inotify to reliably count file events.
The events returned by reading from an inotify file descriptor
form an ordered queue. Thus, for example, it is guaranteed that
when renaming from one directory to another, events will be
produced in the correct order on the inotify file descriptor.
The set of watch descriptors that is being monitored via an
inotify file descriptor can be viewed via the entry for the
inotify file descriptor in the process's /proc/[pid]/fdinfo
directory. See proc(5) for further details. The FIONREAD
ioctl(2) returns the number of bytes available to read from an
inotify file descriptor.
Limitations and caveats
The inotify API provides no information about the user or process
that triggered the inotify event. In particular, there is no
easy way for a process that is monitoring events via inotify to
distinguish events that it triggers itself from those that are
triggered by other processes.
Inotify reports only events that a user-space program triggers
through the filesystem API. As a result, it does not catch
remote events that occur on network filesystems. (Applications
must fall back to polling the filesystem to catch such events.)
Furthermore, various pseudo-filesystems such as /proc, /sys, and
/dev/pts are not monitorable with inotify.
The inotify API does not report file accesses and modifications
that may occur because of mmap(2), msync(2), and munmap(2).
The inotify API identifies affected files by filename. However,
by the time an application processes an inotify event, the
filename may already have been deleted or renamed.
The inotify API identifies events via watch descriptors. It is
the application's responsibility to cache a mapping (if one is
needed) between watch descriptors and pathnames. Be aware that
directory renamings may affect multiple cached pathnames.
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.
If monitoring an entire directory subtree, and a new subdirectory
is created in that tree or an existing directory is renamed into
that tree, be aware that by the time you create a watch for the
new subdirectory, new files (and subdirectories) may already
exist inside the subdirectory. Therefore, you may want to scan
the contents of the subdirectory immediately after adding the
watch (and, if desired, recursively add watches for any
subdirectories that it contains).
Note that the event queue can overflow. In this case, events are
lost. Robust applications should handle the possibility of lost
events gracefully. For example, it may be necessary to rebuild
part or all of the application cache. (One simple, but possibly
expensive, approach is to close the inotify file descriptor,
empty the cache, create a new inotify file descriptor, and then
re-create watches and cache entries for the objects to be
monitored.)
If a filesystem is mounted on top of a monitored directory, no
event is generated, and no events are generated for objects
immediately under the new mount point. If the filesystem is
subsequently unmounted, events will subsequently be generated for
the directory and the objects it contains.
Dealing with rename() events
As noted above, the IN_MOVED_FROM
and IN_MOVED_TO
event pair that
is generated by rename(2) can be matched up via their shared
cookie value. However, the task of matching has some challenges.
These two events are usually consecutive in the event stream
available when reading from the inotify file descriptor.
However, this is not guaranteed. If multiple processes are
triggering events for monitored objects, then (on rare occasions)
an arbitrary number of other events may appear between the
IN_MOVED_FROM
and IN_MOVED_TO
events. Furthermore, it is not
guaranteed that the event pair is atomically inserted into the
queue: there may be a brief interval where the IN_MOVED_FROM
has
appeared, but the IN_MOVED_TO
has not.
Matching up the IN_MOVED_FROM
and IN_MOVED_TO
event pair
generated by rename(2) is thus inherently racy. (Don't forget
that if an object is renamed outside of a monitored directory,
there may not even be an IN_MOVED_TO
event.) Heuristic
approaches (e.g., assume the events are always consecutive) can
be used to ensure a match in most cases, but will inevitably miss
some cases, causing the application to perceive the IN_MOVED_FROM
and IN_MOVED_TO
events as being unrelated. If watch descriptors
are destroyed and re-created as a result, then those watch
descriptors will be inconsistent with the watch descriptors in
any pending events. (Re-creating the inotify file descriptor and
rebuilding the cache may be useful to deal with this scenario.)
Applications should also allow for the possibility that the
IN_MOVED_FROM
event was the last event that could fit in the
buffer returned by the current call to read(2), and the
accompanying IN_MOVED_TO
event might be fetched only on the next
read(2), which should be done with a (small) timeout to allow for
the fact that insertion of the IN_MOVED_FROM
+IN_MOVED_TO
event
pair is not atomic, and also the possibility that there may not
be any IN_MOVED_TO
event.