diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 19:40:15 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 19:40:15 +0000 |
commit | 399644e47874bff147afb19c89228901ac39340e (patch) | |
tree | 1c4c0b733f4c16b5783b41bebb19194a9ef62ad1 /man7/inotify.7 | |
parent | Initial commit. (diff) | |
download | manpages-upstream/6.05.01.tar.xz manpages-upstream/6.05.01.zip |
Adding upstream version 6.05.01.upstream/6.05.01
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | man7/inotify.7 | 1100 |
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 |