summaryrefslogtreecommitdiffstats
path: root/man7/inotify.7
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--man7/inotify.71100
1 files changed, 1100 insertions, 0 deletions
diff --git a/man7/inotify.7 b/man7/inotify.7
new file mode 100644
index 0000000..73a6ab0
--- /dev/null
+++ b/man7/inotify.7
@@ -0,0 +1,1100 @@
+.\" Copyright (C) 2006, 2014 Michael Kerrisk <mtk.manpages@gmail.com>
+.\" Copyright (C) 2014 Heinrich Schuchardt <xypron.glpk@gmx.de>
+.\"
+.\" SPDX-License-Identifier: Linux-man-pages-copyleft
+.\"
+.TH inotify 7 2023-07-08 "Linux man-pages 6.05.01"
+.SH NAME
+inotify \- monitoring filesystem events
+.SH DESCRIPTION
+The
+.I inotify
+API provides a mechanism for monitoring filesystem events.
+Inotify can be used to monitor individual files,
+or to monitor directories.
+When a directory is monitored, inotify will return events
+for the directory itself, and for files inside the directory.
+.PP
+The following system calls are used with this API:
+.IP \[bu] 3
+.BR inotify_init (2)
+creates an inotify instance and returns a file descriptor
+referring to the inotify instance.
+The more recent
+.BR inotify_init1 (2)
+is like
+.BR inotify_init (2),
+but has a
+.I flags
+argument that provides access to some extra functionality.
+.IP \[bu]
+.BR inotify_add_watch (2)
+manipulates the "watch list" associated with an inotify instance.
+Each item ("watch") in the watch list specifies the pathname of
+a file or directory,
+along with some set of events that the kernel should monitor for the
+file referred to by that pathname.
+.BR inotify_add_watch (2)
+either creates a new watch item, or modifies an existing watch.
+Each watch has a unique "watch descriptor", an integer
+returned by
+.BR inotify_add_watch (2)
+when the watch is created.
+.IP \[bu]
+When events occur for monitored files and directories,
+those events are made available to the application as structured data that
+can be read from the inotify file descriptor using
+.BR read (2)
+(see below).
+.IP \[bu]
+.BR inotify_rm_watch (2)
+removes an item from an inotify watch list.
+.IP \[bu]
+When all file descriptors referring to an inotify
+instance have been closed (using
+.BR close (2)),
+the underlying object and its resources are
+freed for reuse by the kernel;
+all associated watches are automatically freed.
+.PP
+With careful programming,
+an application can use inotify to efficiently monitor and cache
+the state of a set of filesystem objects.
+However, robust applications should allow for the fact that bugs
+in the monitoring logic or races of the kind described below
+may leave the cache inconsistent with the filesystem state.
+It is probably wise to do some consistency checking,
+and rebuild the cache when inconsistencies are detected.
+.SS Reading events from an inotify file descriptor
+To determine what events have occurred, an application
+.BR read (2)s
+from the inotify file descriptor.
+If no events have so far occurred, then,
+assuming a blocking file descriptor,
+.BR read (2)
+will block until at least one event occurs
+(unless interrupted by a signal,
+in which case the call fails with the error
+.BR EINTR ;
+see
+.BR signal (7)).
+.PP
+Each successful
+.BR read (2)
+returns a buffer containing one or more of the following structures:
+.PP
+.in +4n
+.EX
+struct inotify_event {
+ int wd; /* Watch descriptor */
+.\" FIXME . The type of the 'wd' field should probably be "int32_t".
+.\" I submitted a patch to fix this. See the LKML thread
+.\" "[patch] Fix type errors in inotify interfaces", 18 Nov 2008
+.\" glibc bug filed: https://www.sourceware.org/bugzilla/show_bug.cgi?id=7040
+ uint32_t mask; /* Mask describing event */
+ uint32_t cookie; /* Unique cookie associating related
+ events (for rename(2)) */
+ uint32_t len; /* Size of \fIname\fP field */
+ char name[]; /* Optional null\-terminated name */
+};
+.EE
+.in
+.PP
+.I wd
+identifies the watch for which this event occurs.
+It is one of the watch descriptors returned by a previous call to
+.BR inotify_add_watch (2).
+.PP
+.I mask
+contains bits that describe the event that occurred (see below).
+.PP
+.I cookie
+is a unique integer that connects related events.
+Currently, this is used only for rename events, and
+allows the resulting pair of
+.B IN_MOVED_FROM
+and
+.B IN_MOVED_TO
+events to be connected by the application.
+For all other event types,
+.I cookie
+is set to 0.
+.PP
+The
+.I name
+field is present only when an event is returned
+for a file inside a watched directory;
+it identifies the filename within the watched directory.
+This filename is null-terminated,
+and may include further null bytes (\[aq]\e0\[aq])
+to align subsequent reads to a suitable address boundary.
+.PP
+The
+.I len
+field counts all of the bytes in
+.IR name ,
+including the null bytes;
+the length of each
+.I inotify_event
+structure is thus
+.IR "sizeof(struct inotify_event)+len" .
+.PP
+The behavior when the buffer given to
+.BR read (2)
+is too small to return information about the next event depends
+on the kernel version: before Linux 2.6.21,
+.BR read (2)
+returns 0; since Linux 2.6.21,
+.BR read (2)
+fails with the error
+.BR EINVAL .
+Specifying a buffer of size
+.PP
+.in +4n
+.EX
+sizeof(struct inotify_event) + NAME_MAX + 1
+.EE
+.in
+.PP
+will be sufficient to read at least one event.
+.SS inotify events
+The
+.BR inotify_add_watch (2)
+.I mask
+argument and the
+.I mask
+field of the
+.I inotify_event
+structure returned when
+.BR read (2)ing
+an inotify file descriptor are both bit masks identifying
+inotify events.
+The following bits can be specified in
+.I mask
+when calling
+.BR inotify_add_watch (2)
+and may be returned in the
+.I mask
+field returned by
+.BR read (2):
+.RS 4
+.TP
+.BR IN_ACCESS " (+)"
+File was accessed (e.g.,
+.BR read (2),
+.BR execve (2)).
+.TP
+.BR IN_ATTRIB " (*)"
+Metadata changed\[em]for example, permissions (e.g.,
+.BR chmod (2)),
+timestamps (e.g.,
+.BR utimensat (2)),
+extended attributes
+.RB ( setxattr (2)),
+link count (since Linux 2.6.25; e.g.,
+.\" FIXME .
+.\" Events do not occur for link count changes on a file inside a monitored
+.\" directory. This differs from other metadata changes for files inside
+.\" a monitored directory.
+for the target of
+.BR link (2)
+and for
+.BR unlink (2)),
+and user/group ID (e.g.,
+.BR chown (2)).
+.TP
+.BR IN_CLOSE_WRITE " (+)"
+File opened for writing was closed.
+.TP
+.BR IN_CLOSE_NOWRITE " (*)"
+File or directory not opened for writing was closed.
+.TP
+.BR IN_CREATE " (+)"
+File/directory created in watched directory (e.g.,
+.BR open (2)
+.BR O_CREAT ,
+.BR mkdir (2),
+.BR link (2),
+.BR symlink (2),
+.BR bind (2)
+on a UNIX domain socket).
+.TP
+.BR IN_DELETE " (+)"
+File/directory deleted from watched directory.
+.TP
+.B IN_DELETE_SELF
+Watched file/directory was itself deleted.
+(This event also occurs if an object is moved to another filesystem,
+since
+.BR mv (1)
+in effect copies the file to the other filesystem and
+then deletes it from the original filesystem.)
+In addition, an
+.B IN_IGNORED
+event will subsequently be generated for the watch descriptor.
+.TP
+.BR IN_MODIFY " (+)"
+File was modified (e.g.,
+.BR write (2),
+.BR truncate (2)).
+.TP
+.B IN_MOVE_SELF
+Watched file/directory was itself moved.
+.TP
+.BR IN_MOVED_FROM " (+)"
+Generated for the directory containing the old filename
+when a file is renamed.
+.TP
+.BR IN_MOVED_TO " (+)"
+Generated for the directory containing the new filename
+when a file is renamed.
+.TP
+.BR IN_OPEN " (*)"
+File or directory was opened.
+.RE
+.PP
+Inotify monitoring is inode-based: when monitoring a file
+(but not when monitoring the directory containing a file),
+an event can be generated for activity on any link to the file
+(in the same or a different directory).
+.PP
+When monitoring a directory:
+.IP \[bu] 3
+the events marked above with an asterisk (*) can occur both
+for the directory itself and for objects inside the directory; and
+.IP \[bu]
+the events marked with a plus sign (+) occur only for objects
+inside the directory (not for the directory itself).
+.PP
+.IR Note :
+when monitoring a directory,
+events are not generated for the files inside the directory
+when the events are performed via a pathname (i.e., a link)
+that lies outside the monitored directory.
+.PP
+When events are generated for objects inside a watched directory, the
+.I name
+field in the returned
+.I inotify_event
+structure identifies the name of the file within the directory.
+.PP
+The
+.B IN_ALL_EVENTS
+macro is defined as a bit mask of all of the above events.
+This macro can be used as the
+.I mask
+argument when calling
+.BR inotify_add_watch (2).
+.PP
+Two additional convenience macros are defined:
+.RS 4
+.TP
+.B IN_MOVE
+Equates to
+.BR "IN_MOVED_FROM | IN_MOVED_TO" .
+.TP
+.B IN_CLOSE
+Equates to
+.BR "IN_CLOSE_WRITE | IN_CLOSE_NOWRITE" .
+.RE
+.PP
+The following further bits can be specified in
+.I mask
+when calling
+.BR inotify_add_watch (2):
+.RS 4
+.TP
+.BR IN_DONT_FOLLOW " (since Linux 2.6.15)"
+Don't dereference
+.I pathname
+if it is a symbolic link.
+.TP
+.BR IN_EXCL_UNLINK " (since Linux 2.6.36)"
+.\" commit 8c1934c8d70b22ca8333b216aec6c7d09fdbd6a6
+By default, when watching events on the children of a directory,
+events are generated for children even after they have been unlinked
+from the directory.
+This can result in large numbers of uninteresting events for
+some applications (e.g., if watching
+.IR /tmp ,
+in which many applications create temporary files whose
+names are immediately unlinked).
+Specifying
+.B IN_EXCL_UNLINK
+changes the default behavior,
+so that events are not generated for children after
+they have been unlinked from the watched directory.
+.TP
+.B IN_MASK_ADD
+If a watch instance already exists for the filesystem object corresponding to
+.IR pathname ,
+add (OR) the events in
+.I mask
+to the watch mask (instead of replacing the mask);
+the error
+.B EINVAL
+results if
+.B IN_MASK_CREATE
+is also specified.
+.TP
+.B IN_ONESHOT
+Monitor the filesystem object corresponding to
+.I pathname
+for one event, then remove from
+watch list.
+.TP
+.BR IN_ONLYDIR " (since Linux 2.6.15)"
+Watch
+.I pathname
+only if it is a directory;
+the error
+.B ENOTDIR
+results if
+.I pathname
+is not a directory.
+Using this flag provides an application with a race-free way of
+ensuring that the monitored object is a directory.
+.TP
+.BR IN_MASK_CREATE " (since Linux 4.18)"
+Watch
+.I pathname
+only if it does not already have a watch associated with it;
+the error
+.B EEXIST
+results if
+.I pathname
+is already being watched.
+.IP
+Using this flag provides an application with a way of ensuring
+that new watches do not modify existing ones.
+This is useful because multiple paths may refer to the same inode,
+and multiple calls to
+.BR inotify_add_watch (2)
+without this flag may clobber existing watch masks.
+.RE
+.PP
+The following bits may be set in the
+.I mask
+field returned by
+.BR read (2):
+.RS 4
+.TP
+.B IN_IGNORED
+Watch was removed explicitly
+.RB ( inotify_rm_watch (2))
+or automatically (file was deleted, or filesystem was unmounted).
+See also BUGS.
+.TP
+.B IN_ISDIR
+Subject of this event is a directory.
+.TP
+.B IN_Q_OVERFLOW
+Event queue overflowed
+.RI ( wd
+is \-1 for this event).
+.TP
+.B IN_UNMOUNT
+Filesystem containing watched object was unmounted.
+In addition, an
+.B IN_IGNORED
+event will subsequently be generated for the watch descriptor.
+.RE
+.SS Examples
+Suppose an application is watching the directory
+.I dir
+and the file
+.I dir/myfile
+for all events.
+The examples below show some events that will be generated
+for these two objects.
+.RS 4
+.TP
+fd = open("dir/myfile", O_RDWR);
+Generates
+.B IN_OPEN
+events for both
+.I dir
+and
+.IR dir/myfile .
+.TP
+read(fd, buf, count);
+Generates
+.B IN_ACCESS
+events for both
+.I dir
+and
+.IR dir/myfile .
+.TP
+write(fd, buf, count);
+Generates
+.B IN_MODIFY
+events for both
+.I dir
+and
+.IR dir/myfile .
+.TP
+fchmod(fd, mode);
+Generates
+.B IN_ATTRIB
+events for both
+.I dir
+and
+.IR dir/myfile .
+.TP
+close(fd);
+Generates
+.B IN_CLOSE_WRITE
+events for both
+.I dir
+and
+.IR dir/myfile .
+.RE
+.PP
+Suppose an application is watching the directories
+.I dir1
+and
+.IR dir2 ,
+and the file
+.IR dir1/myfile .
+The following examples show some events that may be generated.
+.RS 4
+.TP
+link("dir1/myfile", "dir2/new");
+Generates an
+.B IN_ATTRIB
+event for
+.I myfile
+and an
+.B IN_CREATE
+event for
+.IR dir2 .
+.TP
+rename("dir1/myfile", "dir2/myfile");
+Generates an
+.B IN_MOVED_FROM
+event for
+.IR dir1 ,
+an
+.B IN_MOVED_TO
+event for
+.IR dir2 ,
+and an
+.B IN_MOVE_SELF
+event for
+.IR myfile .
+The
+.B IN_MOVED_FROM
+and
+.B IN_MOVED_TO
+events will have the same
+.I cookie
+value.
+.RE
+.PP
+Suppose that
+.I dir1/xx
+and
+.I dir2/yy
+are (the only) links to the same file, and an application is watching
+.IR dir1 ,
+.IR dir2 ,
+.IR dir1/xx ,
+and
+.IR dir2/yy .
+Executing the following calls in the order given below will generate
+the following events:
+.RS 4
+.TP
+unlink("dir2/yy");
+Generates an
+.B IN_ATTRIB
+event for
+.I xx
+(because its link count changes)
+and an
+.B IN_DELETE
+event for
+.IR dir2 .
+.TP
+unlink("dir1/xx");
+Generates
+.BR IN_ATTRIB ,
+.BR IN_DELETE_SELF ,
+and
+.B IN_IGNORED
+events for
+.IR xx ,
+and an
+.B IN_DELETE
+event for
+.IR dir1 .
+.RE
+.PP
+Suppose an application is watching the directory
+.I dir
+and (the empty) directory
+.IR dir/subdir .
+The following examples show some events that may be generated.
+.RS 4
+.TP
+mkdir("dir/new", mode);
+Generates an
+.B "IN_CREATE | IN_ISDIR"
+event for
+.IR dir .
+.TP
+rmdir("dir/subdir");
+Generates
+.B IN_DELETE_SELF
+and
+.B IN_IGNORED
+events for
+.IR subdir ,
+and an
+.B "IN_DELETE | IN_ISDIR"
+event for
+.IR dir .
+.RE
+.SS /proc interfaces
+The following interfaces can be used to limit the amount of
+kernel memory consumed by inotify:
+.TP
+.I /proc/sys/fs/inotify/max_queued_events
+The value in this file is used when an application calls
+.BR inotify_init (2)
+to set an upper limit on the number of events that can be
+queued to the corresponding inotify instance.
+Events in excess of this limit are dropped, but an
+.B IN_Q_OVERFLOW
+event is always generated.
+.TP
+.I /proc/sys/fs/inotify/max_user_instances
+This specifies an upper limit on the number of inotify instances
+that can be created per real user ID.
+.TP
+.I /proc/sys/fs/inotify/max_user_watches
+This specifies an upper limit on the number of watches
+that can be created per real user ID.
+.SH STANDARDS
+Linux.
+.SH HISTORY
+Inotify was merged into Linux 2.6.13.
+The required library interfaces were added in glibc 2.4.
+.RB ( IN_DONT_FOLLOW ,
+.BR IN_MASK_ADD ,
+and
+.B IN_ONLYDIR
+were added in glibc 2.5.)
+.SH NOTES
+Inotify file descriptors can be monitored using
+.BR select (2),
+.BR poll (2),
+and
+.BR epoll (7).
+When an event is available, the file descriptor indicates as readable.
+.PP
+Since Linux 2.6.25,
+signal-driven I/O notification is available for inotify file descriptors;
+see the discussion of
+.B F_SETFL
+(for setting the
+.B O_ASYNC
+flag),
+.BR F_SETOWN ,
+and
+.B F_SETSIG
+in
+.BR fcntl (2).
+The
+.I siginfo_t
+structure (described in
+.BR sigaction (2))
+that is passed to the signal handler has the following fields set:
+.I si_fd
+is set to the inotify file descriptor number;
+.I si_signo
+is set to the signal number;
+.I si_code
+is set to
+.BR POLL_IN ;
+and
+.B POLLIN
+is set in
+.IR si_band .
+.PP
+If successive output inotify events produced on the
+inotify file descriptor are identical (same
+.IR wd ,
+.IR mask ,
+.IR cookie ,
+and
+.IR 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.
+.PP
+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.
+.PP
+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
+.IR /proc/ pid /fdinfo
+directory.
+See
+.BR proc (5)
+for further details.
+The
+.B FIONREAD
+.BR ioctl (2)
+returns the number of bytes available to read from an
+inotify file descriptor.
+.SS 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.
+.PP
+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
+.IR /proc ,
+.IR /sys ,
+and
+.I /dev/pts
+are not monitorable with inotify.
+.PP
+The inotify API does not report file accesses and modifications that
+may occur because of
+.BR mmap (2),
+.BR msync (2),
+and
+.BR munmap (2).
+.PP
+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.
+.PP
+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.
+.PP
+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.
+.PP
+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).
+.PP
+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.)
+.PP
+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.
+.\"
+.SS Dealing with rename() events
+As noted above, the
+.B IN_MOVED_FROM
+and
+.B IN_MOVED_TO
+event pair that is generated by
+.BR rename (2)
+can be matched up via their shared cookie value.
+However, the task of matching has some challenges.
+.PP
+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
+.B IN_MOVED_FROM
+and
+.B 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
+.B IN_MOVED_FROM
+has appeared, but the
+.B IN_MOVED_TO
+has not.
+.PP
+Matching up the
+.B IN_MOVED_FROM
+and
+.B IN_MOVED_TO
+event pair generated by
+.BR 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
+.B 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
+.B IN_MOVED_FROM
+and
+.B 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.)
+.PP
+Applications should also allow for the possibility that the
+.B IN_MOVED_FROM
+event was the last event that could fit in the buffer
+returned by the current call to
+.BR read (2),
+and the accompanying
+.B IN_MOVED_TO
+event might be fetched only on the next
+.BR read (2),
+which should be done with a (small) timeout to allow for the fact that
+insertion of the
+.BR IN_MOVED_FROM + IN_MOVED_TO
+event pair is not atomic,
+and also the possibility that there may not be any
+.B IN_MOVED_TO
+event.
+.SH BUGS
+Before Linux 3.19,
+.BR fallocate (2)
+did not create any inotify events.
+Since Linux 3.19,
+.\" commit 820c12d5d6c0890bc93dd63893924a13041fdc35
+calls to
+.BR fallocate (2)
+generate
+.B IN_MODIFY
+events.
+.PP
+.\" FIXME . kernel commit 611da04f7a31b2208e838be55a42c7a1310ae321
+.\" implies that unmount events were buggy since Linux 2.6.11 to Linux 2.6.36
+.\"
+Before Linux 2.6.16, the
+.B IN_ONESHOT
+.I mask
+flag does not work.
+.PP
+As originally designed and implemented, the
+.B IN_ONESHOT
+flag did not cause an
+.B IN_IGNORED
+event to be generated when the watch was dropped after one event.
+However, as an unintended effect of other changes,
+since Linux 2.6.36, an
+.B IN_IGNORED
+event is generated in this case.
+.PP
+Before Linux 2.6.25,
+.\" commit 1c17d18e3775485bf1e0ce79575eb637a94494a2
+the kernel code that was intended to coalesce successive identical events
+(i.e., the two most recent events could potentially be coalesced
+if the older had not yet been read)
+instead checked if the most recent event could be coalesced with the
+.I oldest
+unread event.
+.PP
+When a watch descriptor is removed by calling
+.BR inotify_rm_watch (2)
+(or because a watch file is deleted or the filesystem
+that contains it is unmounted),
+any pending unread events for that watch descriptor remain available to read.
+As watch descriptors are subsequently allocated with
+.BR inotify_add_watch (2),
+the kernel cycles through the range of possible watch descriptors (1 to
+.BR INT_MAX )
+incrementally.
+When allocating a free watch descriptor, no check is made to see whether that
+watch descriptor number has any pending unread events in the inotify queue.
+Thus, it can happen that a watch descriptor is reallocated even
+when pending unread events exist for a previous incarnation of
+that watch descriptor number, with the result that the application
+might then read those events and interpret them as belonging to
+the file associated with the newly recycled watch descriptor.
+In practice, the likelihood of hitting this bug may be extremely low,
+since it requires that an application cycle through
+.B INT_MAX
+watch descriptors,
+release a watch descriptor while leaving unread events for that
+watch descriptor in the queue,
+and then recycle that watch descriptor.
+For this reason, and because there have been no reports
+of the bug occurring in real-world applications,
+as of Linux 3.15,
+.\" FIXME . https://bugzilla.kernel.org/show_bug.cgi?id=77111
+no kernel changes have yet been made to eliminate this possible bug.
+.SH EXAMPLES
+The following program demonstrates the usage of the inotify API.
+It marks the directories passed as a command-line arguments
+and waits for events of type
+.BR IN_OPEN ,
+.BR IN_CLOSE_NOWRITE ,
+and
+.BR IN_CLOSE_WRITE .
+.PP
+The following output was recorded while editing the file
+.I /home/user/temp/foo
+and listing directory
+.IR /tmp .
+Before the file and the directory were opened,
+.B IN_OPEN
+events occurred.
+After the file was closed, an
+.B IN_CLOSE_WRITE
+event occurred.
+After the directory was closed, an
+.B IN_CLOSE_NOWRITE
+event occurred.
+Execution of the program ended when the user pressed the ENTER key.
+.SS Example output
+.in +4n
+.EX
+$ \fB./a.out /tmp /home/user/temp\fP
+Press enter key to terminate.
+Listening for events.
+IN_OPEN: /home/user/temp/foo [file]
+IN_CLOSE_WRITE: /home/user/temp/foo [file]
+IN_OPEN: /tmp/ [directory]
+IN_CLOSE_NOWRITE: /tmp/ [directory]
+\&
+Listening for events stopped.
+.EE
+.in
+.SS Program source
+\&
+.EX
+#include <errno.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/inotify.h>
+#include <unistd.h>
+#include <string.h>
+\&
+/* Read all available inotify events from the file descriptor \[aq]fd\[aq].
+ wd is the table of watch descriptors for the directories in argv.
+ argc is the length of wd and argv.
+ argv is the list of watched directories.
+ Entry 0 of wd and argv is unused. */
+\&
+static void
+handle_events(int fd, int *wd, int argc, char* argv[])
+{
+ /* Some systems cannot read integer variables if they are not
+ properly aligned. On other systems, incorrect alignment may
+ decrease performance. Hence, the buffer used for reading from
+ the inotify file descriptor should have the same alignment as
+ struct inotify_event. */
+\&
+ char buf[4096]
+ __attribute__ ((aligned(__alignof__(struct inotify_event))));
+ const struct inotify_event *event;
+ ssize_t len;
+\&
+ /* Loop while events can be read from inotify file descriptor. */
+\&
+ for (;;) {
+\&
+ /* Read some events. */
+\&
+ len = read(fd, buf, sizeof(buf));
+ if (len == \-1 && errno != EAGAIN) {
+ perror("read");
+ exit(EXIT_FAILURE);
+ }
+\&
+ /* If the nonblocking read() found no events to read, then
+ it returns \-1 with errno set to EAGAIN. In that case,
+ we exit the loop. */
+\&
+ if (len <= 0)
+ break;
+\&
+ /* Loop over all events in the buffer. */
+\&
+ for (char *ptr = buf; ptr < buf + len;
+ ptr += sizeof(struct inotify_event) + event\->len) {
+\&
+ event = (const struct inotify_event *) ptr;
+\&
+ /* Print event type. */
+\&
+ if (event\->mask & IN_OPEN)
+ printf("IN_OPEN: ");
+ if (event\->mask & IN_CLOSE_NOWRITE)
+ printf("IN_CLOSE_NOWRITE: ");
+ if (event\->mask & IN_CLOSE_WRITE)
+ printf("IN_CLOSE_WRITE: ");
+\&
+ /* Print the name of the watched directory. */
+\&
+ for (size_t i = 1; i < argc; ++i) {
+ if (wd[i] == event\->wd) {
+ printf("%s/", argv[i]);
+ break;
+ }
+ }
+\&
+ /* Print the name of the file. */
+\&
+ if (event\->len)
+ printf("%s", event\->name);
+\&
+ /* Print type of filesystem object. */
+\&
+ if (event\->mask & IN_ISDIR)
+ printf(" [directory]\en");
+ else
+ printf(" [file]\en");
+ }
+ }
+}
+\&
+int
+main(int argc, char* argv[])
+{
+ char buf;
+ int fd, i, poll_num;
+ int *wd;
+ nfds_t nfds;
+ struct pollfd fds[2];
+\&
+ if (argc < 2) {
+ printf("Usage: %s PATH [PATH ...]\en", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+\&
+ printf("Press ENTER key to terminate.\en");
+\&
+ /* Create the file descriptor for accessing the inotify API. */
+\&
+ fd = inotify_init1(IN_NONBLOCK);
+ if (fd == \-1) {
+ perror("inotify_init1");
+ exit(EXIT_FAILURE);
+ }
+\&
+ /* Allocate memory for watch descriptors. */
+\&
+ wd = calloc(argc, sizeof(int));
+ if (wd == NULL) {
+ perror("calloc");
+ exit(EXIT_FAILURE);
+ }
+\&
+ /* Mark directories for events
+ \- file was opened
+ \- file was closed */
+\&
+ for (i = 1; i < argc; i++) {
+ wd[i] = inotify_add_watch(fd, argv[i],
+ IN_OPEN | IN_CLOSE);
+ if (wd[i] == \-1) {
+ fprintf(stderr, "Cannot watch \[aq]%s\[aq]: %s\en",
+ argv[i], strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+\&
+ /* Prepare for polling. */
+\&
+ nfds = 2;
+\&
+ fds[0].fd = STDIN_FILENO; /* Console input */
+ fds[0].events = POLLIN;
+\&
+ fds[1].fd = fd; /* Inotify input */
+ fds[1].events = POLLIN;
+\&
+ /* Wait for events and/or terminal input. */
+\&
+ printf("Listening for events.\en");
+ while (1) {
+ poll_num = poll(fds, nfds, \-1);
+ if (poll_num == \-1) {
+ if (errno == EINTR)
+ continue;
+ perror("poll");
+ exit(EXIT_FAILURE);
+ }
+\&
+ if (poll_num > 0) {
+\&
+ if (fds[0].revents & POLLIN) {
+\&
+ /* Console input is available. Empty stdin and quit. */
+\&
+ while (read(STDIN_FILENO, &buf, 1) > 0 && buf != \[aq]\en\[aq])
+ continue;
+ break;
+ }
+\&
+ if (fds[1].revents & POLLIN) {
+\&
+ /* Inotify events are available. */
+\&
+ handle_events(fd, wd, argc, argv);
+ }
+ }
+ }
+\&
+ printf("Listening for events stopped.\en");
+\&
+ /* Close inotify file descriptor. */
+\&
+ close(fd);
+\&
+ free(wd);
+ exit(EXIT_SUCCESS);
+}
+.EE
+.SH SEE ALSO
+.BR inotifywait (1),
+.BR inotifywatch (1),
+.BR inotify_add_watch (2),
+.BR inotify_init (2),
+.BR inotify_init1 (2),
+.BR inotify_rm_watch (2),
+.BR read (2),
+.BR stat (2),
+.BR fanotify (7)
+.PP
+.I Documentation/filesystems/inotify.txt
+in the Linux kernel source tree