summaryrefslogtreecommitdiffstats
path: root/man/man7/fanotify.7
diff options
context:
space:
mode:
Diffstat (limited to 'man/man7/fanotify.7')
-rw-r--r--man/man7/fanotify.71456
1 files changed, 1456 insertions, 0 deletions
diff --git a/man/man7/fanotify.7 b/man/man7/fanotify.7
new file mode 100644
index 0000000..c08ce33
--- /dev/null
+++ b/man/man7/fanotify.7
@@ -0,0 +1,1456 @@
+.\" Copyright (C) 2013, Heinrich Schuchardt <xypron.glpk@gmx.de>
+.\" and Copyright (C) 2014, Michael Kerrisk <mtk.manpages@gmail.com>
+.\"
+.\" SPDX-License-Identifier: Linux-man-pages-copyleft
+.TH fanotify 7 2024-05-02 "Linux man-pages (unreleased)"
+.SH NAME
+fanotify \- monitoring filesystem events
+.SH DESCRIPTION
+The fanotify API provides notification and interception of
+filesystem events.
+Use cases include virus scanning and hierarchical storage management.
+In the original fanotify API, only a limited set of events was supported.
+In particular, there was no support for create, delete, and move events.
+The support for those events was added in Linux 5.1.
+(See
+.BR inotify (7)
+for details of an API that did notify those events pre Linux 5.1.)
+.P
+Additional capabilities compared to the
+.BR inotify (7)
+API include the ability to monitor all of the objects
+in a mounted filesystem,
+the ability to make access permission decisions, and the
+possibility to read or modify files before access by other applications.
+.P
+The following system calls are used with this API:
+.BR fanotify_init (2),
+.BR fanotify_mark (2),
+.BR read (2),
+.BR write (2),
+and
+.BR close (2).
+.SS fanotify_init(), fanotify_mark(), and notification groups
+The
+.BR fanotify_init (2)
+system call creates and initializes an fanotify notification group
+and returns a file descriptor referring to it.
+.P
+An fanotify notification group is a kernel-internal object that holds
+a list of files, directories, filesystems, and mounts for which
+events shall be created.
+.P
+For each entry in an fanotify notification group, two bit masks exist: the
+.I mark
+mask and the
+.I ignore
+mask.
+The mark mask defines file activities for which an event shall be created.
+The ignore mask defines activities for which no event shall be generated.
+Having these two types of masks permits a filesystem, mount, or
+directory to be marked for receiving events, while at the same time
+ignoring events for specific objects under a mount or directory.
+.P
+The
+.BR fanotify_mark (2)
+system call adds a file, directory, filesystem, or mount to a
+notification group and specifies which events
+shall be reported (or ignored), or removes or modifies such an entry.
+.P
+A possible usage of the ignore mask is for a file cache.
+Events of interest for a file cache are modification of a file and closing
+of the same.
+Hence, the cached directory or mount is to be marked to receive these
+events.
+After receiving the first event informing that a file has been modified,
+the corresponding cache entry will be invalidated.
+No further modification events for this file are of interest until the file
+is closed.
+Hence, the modify event can be added to the ignore mask.
+Upon receiving the close event, the modify event can be removed from the
+ignore mask and the file cache entry can be updated.
+.P
+The entries in the fanotify notification groups refer to files and
+directories via their inode number and to mounts via their mount ID.
+If files or directories are renamed or moved within the same mount,
+the respective entries survive.
+If files or directories are deleted or moved to another mount or if
+filesystems or mounts are unmounted, the corresponding entries are deleted.
+.SS The event queue
+As events occur on the filesystem objects monitored by a notification group,
+the fanotify system generates events that are collected in a queue.
+These events can then be read (using
+.BR read (2)
+or similar)
+from the fanotify file descriptor
+returned by
+.BR fanotify_init (2).
+.P
+Two types of events are generated:
+.I notification
+events and
+.I permission
+events.
+Notification events are merely informative and require no action to be taken
+by the receiving application with one exception: if a valid file descriptor
+is provided within a generic event, the file descriptor must be closed.
+Permission events are requests to the receiving application to decide
+whether permission for a file access shall be granted.
+For these events, the recipient must write a response which decides whether
+access is granted or not.
+.P
+An event is removed from the event queue of the fanotify group
+when it has been read.
+Permission events that have been read are kept in an internal list of the
+fanotify group until either a permission decision has been taken by
+writing to the fanotify file descriptor or the fanotify file descriptor
+is closed.
+.SS Reading fanotify events
+Calling
+.BR read (2)
+for the file descriptor returned by
+.BR fanotify_init (2)
+blocks (if the flag
+.B FAN_NONBLOCK
+is not specified in the call to
+.BR fanotify_init (2))
+until either a file event occurs or the call is interrupted by a signal
+(see
+.BR signal (7)).
+.P
+After a successful
+.BR read (2),
+the read buffer contains one or more of the following structures:
+.P
+.in +4n
+.EX
+struct fanotify_event_metadata {
+ __u32 event_len;
+ __u8 vers;
+ __u8 reserved;
+ __u16 metadata_len;
+ __aligned_u64 mask;
+ __s32 fd;
+ __s32 pid;
+};
+.EE
+.in
+.P
+Information records are
+supplemental pieces of information that
+may be provided alongside the generic
+.I fanotify_event_metadata
+structure.
+The
+.I flags
+passed to
+.BR fanotify_init (2)
+have influence over the type of information records that
+may be returned for an event.
+For example,
+if a notification group is initialized with
+.B FAN_REPORT_FID
+or
+.BR FAN_REPORT_DIR_FID ,
+then event listeners should also expect to receive a
+.I fanotify_event_info_fid
+structure alongside the
+.I fanotify_event_metadata
+structure,
+whereby file handles are used to
+identify filesystem objects
+rather than file descriptors.
+Information records may also be stacked,
+meaning that using the various
+.B FAN_REPORT_*
+flags in conjunction with one another is supported.
+In such cases,
+multiple information records can be returned for an event
+alongside the generic
+.I fanotify_event_metadata
+structure.
+For example,
+if a notification group is initialized with
+.B FAN_REPORT_TARGET_FID
+and
+.BR FAN_REPORT_PIDFD ,
+then an event listener should expect to receive up to two
+.I fanotify_event_info_fid
+information records and one
+.I fanotify_event_info_pidfd
+information record alongside the generic
+.I fanotify_event_metadata
+structure.
+Importantly,
+fanotify provides no guarantee around
+the ordering of information records
+when a notification group is initialized with a
+stacked based configuration.
+Each information record has a nested structure of type
+.IR fanotify_event_info_header .
+It is imperative for event listeners to inspect the
+.I info_type
+field of this structure in order to
+determine the type of information record that
+had been received for a given event.
+.P
+In cases where an fanotify group
+identifies filesystem objects by file handles,
+event listeners should also expect to
+receive one or more of the below
+information record objects alongside the generic
+.I fanotify_event_metadata
+structure within the read buffer:
+.P
+.in +4n
+.EX
+struct fanotify_event_info_fid {
+ struct fanotify_event_info_header hdr;
+ __kernel_fsid_t fsid;
+ unsigned char handle[];
+};
+.EE
+.in
+.P
+In cases where an fanotify group is initialized with
+.BR FAN_REPORT_PIDFD ,
+event listeners should expect to receive the below
+information record object alongside the generic
+.I fanotify_event_metadata
+structure within the read buffer:
+.P
+.in +4n
+.EX
+struct fanotify_event_info_pidfd {
+ struct fanotify_event_info_header hdr;
+ __s32 pidfd;
+};
+.EE
+.in
+.P
+In case of a
+.B FAN_FS_ERROR
+event,
+an additional information record describing the error that occurred
+is returned alongside the generic
+.I fanotify_event_metadata
+structure within the read buffer.
+This structure is defined as follows:
+.P
+.in +4n
+.EX
+struct fanotify_event_info_error {
+ struct fanotify_event_info_header hdr;
+ __s32 error;
+ __u32 error_count;
+};
+.EE
+.in
+.P
+All information records contain a nested structure of type
+.IR fanotify_event_info_header .
+This structure holds meta-information about the information record
+that may have been returned alongside the generic
+.I fanotify_event_metadata
+structure.
+This structure is defined as follows:
+.P
+.in +4n
+.EX
+struct fanotify_event_info_header {
+ __u8 info_type;
+ __u8 pad;
+ __u16 len;
+};
+.EE
+.in
+.P
+For performance reasons, it is recommended to use a large
+buffer size (for example, 4096 bytes),
+so that multiple events can be retrieved by a single
+.BR read (2).
+.P
+The return value of
+.BR read (2)
+is the number of bytes placed in the buffer,
+or \-1 in case of an error (but see BUGS).
+.P
+The fields of the
+.I fanotify_event_metadata
+structure are as follows:
+.TP
+.I event_len
+This is the length of the data for the current event and the offset
+to the next event in the buffer.
+Unless the group identifies filesystem objects by file handles, the value of
+.I event_len
+is always
+.BR FAN_EVENT_METADATA_LEN .
+For a group that identifies filesystem objects by file handles,
+.I event_len
+also includes the variable length file identifier records.
+.TP
+.I vers
+This field holds a version number for the structure.
+It must be compared to
+.B FANOTIFY_METADATA_VERSION
+to verify that the structures returned at run time match
+the structures defined at compile time.
+In case of a mismatch, the application should abandon trying to use the
+fanotify file descriptor.
+.TP
+.I reserved
+This field is not used.
+.TP
+.I metadata_len
+This is the length of the structure.
+The field was introduced to facilitate the implementation of
+optional headers per event type.
+No such optional headers exist in the current implementation.
+.TP
+.I mask
+This is a bit mask describing the event (see below).
+.TP
+.I fd
+This is an open file descriptor for the object being accessed, or
+.B FAN_NOFD
+if a queue overflow occurred.
+With an fanotify group that identifies filesystem objects by file handles,
+applications should expect this value to be set to
+.B FAN_NOFD
+for each event that is received.
+The file descriptor can be used to access the contents
+of the monitored file or directory.
+The reading application is responsible for closing this file descriptor.
+.IP
+When calling
+.BR fanotify_init (2),
+the caller may specify (via the
+.I event_f_flags
+argument) various file status flags that are to be set
+on the open file description that corresponds to this file descriptor.
+In addition, the (kernel-internal)
+.B FMODE_NONOTIFY
+file status flag is set on the open file description.
+This flag suppresses fanotify event generation.
+Hence, when the receiver of the fanotify event accesses the notified file or
+directory using this file descriptor, no additional events will be created.
+.TP
+.I pid
+If flag
+.B FAN_REPORT_TID
+was set in
+.BR fanotify_init (2),
+this is the TID of the thread that caused the event.
+Otherwise, this the PID of the process that caused the event.
+.P
+A program listening to fanotify events can compare this PID
+to the PID returned by
+.BR getpid (2),
+to determine whether the event is caused by the listener itself,
+or is due to a file access by another process.
+.P
+The bit mask in
+.I mask
+indicates which events have occurred for a single filesystem object.
+Multiple bits may be set in this mask,
+if more than one event occurred for the monitored filesystem object.
+In particular,
+consecutive events for the same filesystem object and originating from the
+same process may be merged into a single event, with the exception that two
+permission events are never merged into one queue entry.
+.P
+The bits that may appear in
+.I mask
+are as follows:
+.TP
+.B FAN_ACCESS
+A file or a directory (but see BUGS) was accessed (read).
+.TP
+.B FAN_OPEN
+A file or a directory was opened.
+.TP
+.B FAN_OPEN_EXEC
+A file was opened with the intent to be executed.
+See NOTES in
+.BR fanotify_mark (2)
+for additional details.
+.TP
+.B FAN_ATTRIB
+A file or directory metadata was changed.
+.TP
+.B FAN_CREATE
+A child file or directory was created in a watched parent.
+.TP
+.B FAN_DELETE
+A child file or directory was deleted in a watched parent.
+.TP
+.B FAN_DELETE_SELF
+A watched file or directory was deleted.
+.TP
+.B FAN_FS_ERROR
+A filesystem error was detected.
+.TP
+.B FAN_RENAME
+A file or directory has been moved to or from a watched parent directory.
+.TP
+.B FAN_MOVED_FROM
+A file or directory has been moved from a watched parent directory.
+.TP
+.B FAN_MOVED_TO
+A file or directory has been moved to a watched parent directory.
+.TP
+.B FAN_MOVE_SELF
+A watched file or directory was moved.
+.TP
+.B FAN_MODIFY
+A file was modified.
+.TP
+.B FAN_CLOSE_WRITE
+A file that was opened for writing
+.RB ( O_WRONLY
+or
+.BR O_RDWR )
+was closed.
+.TP
+.B FAN_CLOSE_NOWRITE
+A file or directory that was opened read-only
+.RB ( O_RDONLY )
+was closed.
+.TP
+.B FAN_Q_OVERFLOW
+The event queue exceeded the limit on number of events.
+This limit can be overridden by specifying the
+.B FAN_UNLIMITED_QUEUE
+flag when calling
+.BR fanotify_init (2).
+.TP
+.B FAN_ACCESS_PERM
+An application wants to read a file or directory, for example using
+.BR read (2)
+or
+.BR readdir (2).
+The reader must write a response (as described below)
+that determines whether the permission to
+access the filesystem object shall be granted.
+.TP
+.B FAN_OPEN_PERM
+An application wants to open a file or directory.
+The reader must write a response that determines whether the permission to
+open the filesystem object shall be granted.
+.TP
+.B FAN_OPEN_EXEC_PERM
+An application wants to open a file for execution.
+The reader must write a response that determines whether the permission to
+open the filesystem object for execution shall be granted.
+See NOTES in
+.BR fanotify_mark (2)
+for additional details.
+.P
+To check for any close event, the following bit mask may be used:
+.TP
+.B FAN_CLOSE
+A file was closed.
+This is a synonym for:
+.IP
+.in +4n
+.EX
+FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE
+.EE
+.in
+.P
+To check for any move event, the following bit mask may be used:
+.TP
+.B FAN_MOVE
+A file or directory was moved.
+This is a synonym for:
+.IP
+.in +4n
+.EX
+FAN_MOVED_FROM | FAN_MOVED_TO
+.EE
+.in
+.P
+The following bits may appear in
+.I mask
+only in conjunction with other event type bits:
+.TP
+.B FAN_ONDIR
+The events described in the
+.I mask
+have occurred on a directory object.
+Reporting events on directories requires setting this flag in the mark mask.
+See
+.BR fanotify_mark (2)
+for additional details.
+The
+.B FAN_ONDIR
+flag is reported in an event mask only if the fanotify group identifies
+filesystem objects by file handles.
+.P
+Information records that are supplied alongside the generic
+.I fanotify_event_metadata
+structure will always contain a nested structure of type
+.IR fanotify_event_info_header .
+The fields of the
+.I fanotify_event_info_header
+are as follows:
+.TP
+.I info_type
+A unique integer value representing
+the type of information record object received for an event.
+The value of this field can be set to one of the following:
+.BR FAN_EVENT_INFO_TYPE_FID ,
+.BR FAN_EVENT_INFO_TYPE_DFID ,
+.BR FAN_EVENT_INFO_TYPE_DFID_NAME ,
+or
+.BR FAN_EVENT_INFO_TYPE_PIDFD .
+The value set for this field
+is dependent on the flags that have been supplied to
+.BR fanotify_init (2).
+Refer to the field details of each information record object type below
+to understand the different cases in which the
+.I info_type
+values can be set.
+.TP
+.I pad
+This field is currently not used by any information record object type
+and therefore is set to zero.
+.TP
+.I len
+The value of
+.I len
+is set to the size of the information record object,
+including the
+.IR fanotify_event_info_header .
+The total size of all additional information records
+is not expected to be larger than
+.RI ( event_len
+\-
+.IR metadata_len ).
+.P
+The fields of the
+.I fanotify_event_info_fid
+structure are as follows:
+.TP
+.I hdr
+This is a structure of type
+.IR fanotify_event_info_header .
+For example, when an fanotify file descriptor is created using
+.BR FAN_REPORT_FID ,
+a single information record is expected to be attached to the event with
+.I info_type
+field value of
+.BR FAN_EVENT_INFO_TYPE_FID .
+When an fanotify file descriptor is created using the combination of
+.B FAN_REPORT_FID
+and
+.BR FAN_REPORT_DIR_FID ,
+there may be two information records attached to the event:
+one with
+.I info_type
+field value of
+.BR FAN_EVENT_INFO_TYPE_DFID ,
+identifying a parent directory object, and one with
+.I info_type
+field value of
+.BR FAN_EVENT_INFO_TYPE_FID ,
+identifying a child object.
+Note that for the directory entry modification events
+.BR FAN_CREATE ,
+.BR FAN_DELETE ,
+.BR FAN_MOVE ,
+and
+.BR FAN_RENAME ,
+an information record identifying the created/deleted/moved child object
+is reported only if an fanotify group was initialized with the flag
+.BR FAN_REPORT_TARGET_FID .
+.TP
+.I fsid
+This is a unique identifier of the filesystem containing the object
+associated with the event.
+It is a structure of type
+.I __kernel_fsid_t
+and contains the same value as
+.I f_fsid
+when calling
+.BR statfs (2).
+.TP
+.I handle
+This field contains a variable-length structure of type
+.IR "struct file_handle" .
+It is an opaque handle that corresponds to a specified object on a
+filesystem as returned by
+.BR name_to_handle_at (2).
+It can be used to uniquely identify a file on a filesystem and can be
+passed as an argument to
+.BR open_by_handle_at (2).
+If the value of
+.I info_type
+field is
+.BR FAN_EVENT_INFO_TYPE_DFID_NAME ,
+the file handle is followed by a null terminated string that identifies the
+created/deleted/moved directory entry name.
+For other events such as
+.BR FAN_OPEN ,
+.BR FAN_ATTRIB ,
+.BR FAN_DELETE_SELF ,
+and
+.BR FAN_MOVE_SELF ,
+if the value of
+.I info_type
+field is
+.BR FAN_EVENT_INFO_TYPE_FID ,
+the
+.I handle
+identifies the object correlated to the event.
+If the value of
+.I info_type
+field is
+.BR FAN_EVENT_INFO_TYPE_DFID ,
+the
+.I handle
+identifies the directory object correlated to the event or the parent directory
+of a non-directory object correlated to the event.
+If the value of
+.I info_type
+field is
+.BR FAN_EVENT_INFO_TYPE_DFID_NAME ,
+the
+.I handle
+identifies the same directory object that would be reported with
+.B FAN_EVENT_INFO_TYPE_DFID
+and the file handle is followed by a null terminated string that identifies the
+name of a directory entry in that directory, or '.' to identify the directory
+object itself.
+.P
+The fields of the
+.I fanotify_event_info_pidfd
+structure are as follows:
+.TP
+.I hdr
+This is a structure of type
+.IR fanotify_event_info_header .
+When an fanotify group is initialized using
+.BR FAN_REPORT_PIDFD ,
+the
+.I info_type
+field value of the
+.I fanotify_event_info_header
+is set to
+.BR FAN_EVENT_INFO_TYPE_PIDFD .
+.TP
+.I pidfd
+This is a process file descriptor that refers to
+the process responsible for generating the event.
+The returned process file descriptor is no different from
+one which could be obtained manually if
+.BR pidfd_open (2)
+were to be called on
+.IR fanotify_event_metadata.pid .
+In the instance that an error is encountered during pidfd creation,
+one of two possible error types represented by
+a negative integer value may be returned in this
+.I pidfd
+field.
+In cases where
+the process responsible for generating the event
+has terminated prior to
+the event listener being able to
+read events from the notification queue,
+.B FAN_NOPIDFD
+is returned.
+The pidfd creation for an event is only performed at the time the
+events are read from the notification queue.
+All other possible pidfd creation failures are represented by
+.BR FAN_EPIDFD .
+Once the event listener has dealt with an event
+and the pidfd is no longer required,
+the pidfd should be closed via
+.BR close (2).
+.P
+The fields of the
+.I fanotify_event_info_error
+structure are as follows:
+.TP
+.I hdr
+This is a structure of type
+.IR fanotify_event_info_header .
+The
+.I info_type
+field is set to
+.BR FAN_EVENT_INFO_TYPE_ERROR .
+.TP
+.I error
+Identifies the type of error that occurred.
+.TP
+.I error_count
+This is a counter of the number of errors suppressed
+since the last error was read.
+.P
+The following macros are provided to iterate over a buffer containing
+fanotify event metadata returned by a
+.BR read (2)
+from an fanotify file descriptor:
+.TP
+.B FAN_EVENT_OK(meta, len)
+This macro checks the remaining length
+.I len
+of the buffer
+.I meta
+against the length of the metadata structure and the
+.I event_len
+field of the first metadata structure in the buffer.
+.TP
+.B FAN_EVENT_NEXT(meta, len)
+This macro uses the length indicated in the
+.I event_len
+field of the metadata structure pointed to by
+.I meta
+to calculate the address of the next metadata structure that follows
+.IR meta .
+.I len
+is the number of bytes of metadata that currently remain in the buffer.
+The macro returns a pointer to the next metadata structure that follows
+.IR meta ,
+and reduces
+.I len
+by the number of bytes in the metadata structure that
+has been skipped over (i.e., it subtracts
+.I meta\->event_len
+from
+.IR len ).
+.P
+In addition, there is:
+.TP
+.B FAN_EVENT_METADATA_LEN
+This macro returns the size (in bytes) of the structure
+.IR fanotify_event_metadata .
+This is the minimum size (and currently the only size) of any event metadata.
+.\"
+.SS Monitoring an fanotify file descriptor for events
+When an fanotify event occurs, the fanotify file descriptor indicates as
+readable when passed to
+.BR epoll (7),
+.BR poll (2),
+or
+.BR select (2).
+.SS Dealing with permission events
+For permission events, the application must
+.BR write (2)
+a structure of the following form to the
+fanotify file descriptor:
+.P
+.in +4n
+.EX
+struct fanotify_response {
+ __s32 fd;
+ __u32 response;
+};
+.EE
+.in
+.P
+The fields of this structure are as follows:
+.TP
+.I fd
+This is the file descriptor from the structure
+.IR fanotify_event_metadata .
+.TP
+.I response
+This field indicates whether or not the permission is to be granted.
+Its value must be either
+.B FAN_ALLOW
+to allow the file operation or
+.B FAN_DENY
+to deny the file operation.
+.P
+If access is denied, the requesting application call will receive an
+.B EPERM
+error.
+Additionally, if the notification group has been created with the
+.B FAN_ENABLE_AUDIT
+flag, then the
+.B FAN_AUDIT
+flag can be set in the
+.I response
+field.
+In that case, the audit subsystem will log information about the access
+decision to the audit logs.
+.\"
+.SS Monitoring filesystems for errors
+A single
+.B FAN_FS_ERROR
+event is stored per filesystem at once.
+Extra error messages are suppressed and accounted for in the
+.I error_count
+field of the existing
+.B FAN_FS_ERROR
+event record,
+but details about the errors are lost.
+.P
+Errors reported by
+.B FAN_FS_ERROR
+are generic
+.I errno
+values,
+but not all kinds of error types are reported by all filesystems.
+.P
+Errors not directly related to a file (i.e. super block corruption)
+are reported with an invalid
+.IR handle .
+For these errors, the
+.I handle
+will have the field
+.I handle_type
+set to
+.BR FILEID_INVALID ,
+and the handle buffer size set to
+.BR 0 .
+.\"
+.SS Closing the fanotify file descriptor
+When all file descriptors referring to the fanotify notification group are
+closed, the fanotify group is released and its resources
+are freed for reuse by the kernel.
+Upon
+.BR close (2),
+outstanding permission events will be set to allowed.
+.SS /proc interfaces
+The file
+.IR /proc/ pid /fdinfo/ fd
+contains information about fanotify marks for file descriptor
+.I fd
+of process
+.IR pid .
+See
+.BR proc (5)
+for details.
+.P
+Since Linux 5.13,
+.\" commit 5b8fea65d197f408bb00b251c70d842826d6b70b
+the following interfaces can be used to control the amount of
+kernel resources consumed by fanotify:
+.TP
+.I /proc/sys/fs/fanotify/max_queued_events
+The value in this file is used when an application calls
+.BR fanotify_init (2)
+to set an upper limit on the number of events that can be
+queued to the corresponding fanotify group.
+Events in excess of this limit are dropped, but an
+.B FAN_Q_OVERFLOW
+event is always generated.
+Prior to Linux kernel 5.13,
+.\" commit 5b8fea65d197f408bb00b251c70d842826d6b70b
+the hardcoded limit was 16384 events.
+.TP
+.I /proc/sys/fs/fanotify/max_user_group
+This specifies an upper limit on the number of fanotify groups
+that can be created per real user ID.
+Prior to Linux kernel 5.13,
+.\" commit 5b8fea65d197f408bb00b251c70d842826d6b70b
+the hardcoded limit was 128 groups per user.
+.TP
+.I /proc/sys/fs/fanotify/max_user_marks
+This specifies an upper limit on the number of fanotify marks
+that can be created per real user ID.
+Prior to Linux kernel 5.13,
+.\" commit 5b8fea65d197f408bb00b251c70d842826d6b70b
+the hardcoded limit was 8192 marks per group (not per user).
+.SH ERRORS
+In addition to the usual errors for
+.BR read (2),
+the following errors can occur when reading from the
+fanotify file descriptor:
+.TP
+.B EINVAL
+The buffer is too small to hold the event.
+.TP
+.B EMFILE
+The per-process limit on the number of open files has been reached.
+See the description of
+.B RLIMIT_NOFILE
+in
+.BR getrlimit (2).
+.TP
+.B ENFILE
+The system-wide limit on the total number of open files has been reached.
+See
+.I /proc/sys/fs/file\-max
+in
+.BR proc (5).
+.TP
+.B ETXTBSY
+This error is returned by
+.BR read (2)
+if
+.B O_RDWR
+or
+.B O_WRONLY
+was specified in the
+.I event_f_flags
+argument when calling
+.BR fanotify_init (2)
+and an event occurred for a monitored file that is currently being executed.
+.P
+In addition to the usual errors for
+.BR write (2),
+the following errors can occur when writing to the fanotify file descriptor:
+.TP
+.B EINVAL
+Fanotify access permissions are not enabled in the kernel configuration
+or the value of
+.I response
+in the response structure is not valid.
+.TP
+.B ENOENT
+The file descriptor
+.I fd
+in the response structure is not valid.
+This may occur when a response for the permission event has already been
+written.
+.SH STANDARDS
+Linux.
+.SH HISTORY
+The fanotify API was introduced in Linux 2.6.36 and
+enabled in Linux 2.6.37.
+fdinfo support was added in Linux 3.8.
+.SH NOTES
+The fanotify API is available only if the kernel was built with the
+.B CONFIG_FANOTIFY
+configuration option enabled.
+In addition, fanotify permission handling is available only if the
+.B CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+configuration option is enabled.
+.SS Limitations and caveats
+Fanotify 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.
+.P
+The fanotify API does not report file accesses and modifications that
+may occur because of
+.BR mmap (2),
+.BR msync (2),
+and
+.BR munmap (2).
+.P
+Events for directories are created only if the directory itself is opened,
+read, and closed.
+Adding, removing, or changing children of a marked directory does not create
+events for the monitored directory itself.
+.P
+Fanotify monitoring of directories is not recursive:
+to monitor subdirectories under a directory,
+additional marks must be created.
+The
+.B FAN_CREATE
+event can be used for detecting when a subdirectory has been created under
+a marked directory.
+An additional mark must then be set on the newly created subdirectory.
+This approach is racy, because it can lose events that occurred inside the
+newly created subdirectory, before a mark is added on that subdirectory.
+Monitoring mounts offers the capability to monitor a whole directory tree
+in a race-free manner.
+Monitoring filesystems offers the capability to monitor changes made from
+any mount of a filesystem instance in a race-free manner.
+.P
+The event queue can overflow.
+In this case, events are lost.
+.SH BUGS
+Before Linux 3.19,
+.BR fallocate (2)
+did not generate fanotify events.
+Since Linux 3.19,
+.\" commit 820c12d5d6c0890bc93dd63893924a13041fdc35
+calls to
+.BR fallocate (2)
+generate
+.B FAN_MODIFY
+events.
+.P
+As of Linux 3.17,
+the following bugs exist:
+.IP \[bu] 3
+On Linux, a filesystem object may be accessible through multiple paths,
+for example, a part of a filesystem may be remounted using the
+.I \-\-bind
+option of
+.BR mount (8).
+A listener that marked a mount will be notified only of events that were
+triggered for a filesystem object using the same mount.
+Any other event will pass unnoticed.
+.IP \[bu]
+.\" FIXME . A patch was proposed.
+When an event is generated,
+no check is made to see whether the user ID of the
+receiving process has authorization to read or write the file
+before passing a file descriptor for that file.
+This poses a security risk, when the
+.B CAP_SYS_ADMIN
+capability is set for programs executed by unprivileged users.
+.IP \[bu]
+If a call to
+.BR read (2)
+processes multiple events from the fanotify queue and an error occurs,
+the return value will be the total length of the events successfully
+copied to the user-space buffer before the error occurred.
+The return value will not be \-1, and
+.I errno
+will not be set.
+Thus, the reading application has no way to detect the error.
+.SH EXAMPLES
+The two example programs below demonstrate the usage of the fanotify API.
+.SS Example program: fanotify_example.c
+The first program is an example of fanotify being
+used with its event object information passed in the form of a file
+descriptor.
+The program marks the mount passed as a command-line argument and
+waits for events of type
+.B FAN_OPEN_PERM
+and
+.BR FAN_CLOSE_WRITE .
+When a permission event occurs, a
+.B FAN_ALLOW
+response is given.
+.P
+The following shell session shows an example of
+running this program.
+This session involved editing the file
+.IR /home/user/temp/notes .
+Before the file was opened, a
+.B FAN_OPEN_PERM
+event occurred.
+After the file was closed, a
+.B FAN_CLOSE_WRITE
+event occurred.
+Execution of the program ends when the user presses the ENTER key.
+.P
+.in +4n
+.EX
+# \fB./fanotify_example /home\fP
+Press enter key to terminate.
+Listening for events.
+FAN_OPEN_PERM: File /home/user/temp/notes
+FAN_CLOSE_WRITE: File /home/user/temp/notes
+\&
+Listening for events stopped.
+.EE
+.in
+.SS Program source: fanotify_example.c
+\&
+.EX
+#define _GNU_SOURCE /* Needed to get O_LARGEFILE definition */
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/fanotify.h>
+#include <unistd.h>
+\&
+/* Read all available fanotify events from the file descriptor \[aq]fd\[aq]. */
+\&
+static void
+handle_events(int fd)
+{
+ const struct fanotify_event_metadata *metadata;
+ struct fanotify_event_metadata buf[200];
+ ssize_t len;
+ char path[PATH_MAX];
+ ssize_t path_len;
+ char procfd_path[PATH_MAX];
+ struct fanotify_response response;
+\&
+ /* Loop while events can be read from fanotify file descriptor. */
+\&
+ for (;;) {
+\&
+ /* Read some events. */
+\&
+ len = read(fd, buf, sizeof(buf));
+ if (len == \-1 && errno != EAGAIN) {
+ perror("read");
+ exit(EXIT_FAILURE);
+ }
+\&
+ /* Check if end of available data reached. */
+\&
+ if (len <= 0)
+ break;
+\&
+ /* Point to the first event in the buffer. */
+\&
+ metadata = buf;
+\&
+ /* Loop over all events in the buffer. */
+\&
+ while (FAN_EVENT_OK(metadata, len)) {
+\&
+ /* Check that run\-time and compile\-time structures match. */
+\&
+ if (metadata\->vers != FANOTIFY_METADATA_VERSION) {
+ fprintf(stderr,
+ "Mismatch of fanotify metadata version.\en");
+ exit(EXIT_FAILURE);
+ }
+\&
+ /* metadata\->fd contains either FAN_NOFD, indicating a
+ queue overflow, or a file descriptor (a nonnegative
+ integer). Here, we simply ignore queue overflow. */
+\&
+ if (metadata\->fd >= 0) {
+\&
+ /* Handle open permission event. */
+\&
+ if (metadata\->mask & FAN_OPEN_PERM) {
+ printf("FAN_OPEN_PERM: ");
+\&
+ /* Allow file to be opened. */
+\&
+ response.fd = metadata\->fd;
+ response.response = FAN_ALLOW;
+ write(fd, &response, sizeof(response));
+ }
+\&
+ /* Handle closing of writable file event. */
+\&
+ if (metadata\->mask & FAN_CLOSE_WRITE)
+ printf("FAN_CLOSE_WRITE: ");
+\&
+ /* Retrieve and print pathname of the accessed file. */
+\&
+ snprintf(procfd_path, sizeof(procfd_path),
+ "/proc/self/fd/%d", metadata\->fd);
+ path_len = readlink(procfd_path, path,
+ sizeof(path) \- 1);
+ if (path_len == \-1) {
+ perror("readlink");
+ exit(EXIT_FAILURE);
+ }
+\&
+ path[path_len] = \[aq]\e0\[aq];
+ printf("File %s\en", path);
+\&
+ /* Close the file descriptor of the event. */
+\&
+ close(metadata\->fd);
+ }
+\&
+ /* Advance to next event. */
+\&
+ metadata = FAN_EVENT_NEXT(metadata, len);
+ }
+ }
+}
+\&
+int
+main(int argc, char *argv[])
+{
+ char buf;
+ int fd, poll_num;
+ nfds_t nfds;
+ struct pollfd fds[2];
+\&
+ /* Check mount point is supplied. */
+\&
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s MOUNT\en", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+\&
+ printf("Press enter key to terminate.\en");
+\&
+ /* Create the file descriptor for accessing the fanotify API. */
+\&
+ fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
+ O_RDONLY | O_LARGEFILE);
+ if (fd == \-1) {
+ perror("fanotify_init");
+ exit(EXIT_FAILURE);
+ }
+\&
+ /* Mark the mount for:
+ \- permission events before opening files
+ \- notification events after closing a write\-enabled
+ file descriptor. */
+\&
+ if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
+ FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD,
+ argv[1]) == \-1) {
+ perror("fanotify_mark");
+ exit(EXIT_FAILURE);
+ }
+\&
+ /* Prepare for polling. */
+\&
+ nfds = 2;
+\&
+ fds[0].fd = STDIN_FILENO; /* Console input */
+ fds[0].events = POLLIN;
+\&
+ fds[1].fd = fd; /* Fanotify input */
+ fds[1].events = POLLIN;
+\&
+ /* This is the loop to wait for incoming events. */
+\&
+ printf("Listening for events.\en");
+\&
+ while (1) {
+ poll_num = poll(fds, nfds, \-1);
+ if (poll_num == \-1) {
+ if (errno == EINTR) /* Interrupted by a signal */
+ continue; /* Restart poll() */
+\&
+ perror("poll"); /* Unexpected error */
+ 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) {
+\&
+ /* Fanotify events are available. */
+\&
+ handle_events(fd);
+ }
+ }
+ }
+\&
+ printf("Listening for events stopped.\en");
+ exit(EXIT_SUCCESS);
+}
+.EE
+.\"
+.SS Example program: fanotify_fid.c
+The second program is an example of fanotify being used with a group that
+identifies objects by file handles.
+The program marks the filesystem object that is passed as
+a command-line argument
+and waits until an event of type
+.B FAN_CREATE
+has occurred.
+The event mask indicates which type of filesystem object\[em]either
+a file or a directory\[em]was created.
+Once all events have been read from the buffer and processed accordingly,
+the program simply terminates.
+.P
+The following shell sessions show two different invocations of
+this program, with different actions performed on a watched object.
+.P
+The first session shows a mark being placed on
+.IR /home/user .
+This is followed by the creation of a regular file,
+.IR /home/user/testfile.txt .
+This results in a
+.B FAN_CREATE
+event being generated and reported against the file's parent watched
+directory object and with the created file name.
+Program execution ends once all events captured within the buffer have
+been processed.
+.P
+.in +4n
+.EX
+# \fB./fanotify_fid /home/user\fP
+Listening for events.
+FAN_CREATE (file created):
+ Directory /home/user has been modified.
+ Entry \[aq]testfile.txt\[aq] is not a subdirectory.
+All events processed successfully. Program exiting.
+\&
+$ \fBtouch /home/user/testfile.txt\fP # In another terminal
+.EE
+.in
+.P
+The second session shows a mark being placed on
+.IR /home/user .
+This is followed by the creation of a directory,
+.IR /home/user/testdir .
+This specific action results in a
+.B FAN_CREATE
+event being generated and is reported with the
+.B FAN_ONDIR
+flag set and with the created directory name.
+.P
+.in +4n
+.EX
+# \fB./fanotify_fid /home/user\fP
+Listening for events.
+FAN_CREATE | FAN_ONDIR (subdirectory created):
+ Directory /home/user has been modified.
+ Entry \[aq]testdir\[aq] is a subdirectory.
+All events processed successfully. Program exiting.
+\&
+$ \fBmkdir \-p /home/user/testdir\fP # In another terminal
+.EE
+.in
+.SS Program source: fanotify_fid.c
+\&
+.EX
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fanotify.h>
+#include <unistd.h>
+\&
+#define BUF_SIZE 256
+\&
+int
+main(int argc, char *argv[])
+{
+ int fd, ret, event_fd, mount_fd;
+ ssize_t len, path_len;
+ char path[PATH_MAX];
+ char procfd_path[PATH_MAX];
+ char events_buf[BUF_SIZE];
+ struct file_handle *file_handle;
+ struct fanotify_event_metadata *metadata;
+ struct fanotify_event_info_fid *fid;
+ const char *file_name;
+ struct stat sb;
+\&
+ if (argc != 2) {
+ fprintf(stderr, "Invalid number of command line arguments.\en");
+ exit(EXIT_FAILURE);
+ }
+\&
+ mount_fd = open(argv[1], O_DIRECTORY | O_RDONLY);
+ if (mount_fd == \-1) {
+ perror(argv[1]);
+ exit(EXIT_FAILURE);
+ }
+\&
+ /* Create an fanotify file descriptor with FAN_REPORT_DFID_NAME as
+ a flag so that program can receive fid events with directory
+ entry name. */
+\&
+ fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME, 0);
+ if (fd == \-1) {
+ perror("fanotify_init");
+ exit(EXIT_FAILURE);
+ }
+\&
+ /* Place a mark on the filesystem object supplied in argv[1]. */
+\&
+ ret = fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_ONLYDIR,
+ FAN_CREATE | FAN_ONDIR,
+ AT_FDCWD, argv[1]);
+ if (ret == \-1) {
+ perror("fanotify_mark");
+ exit(EXIT_FAILURE);
+ }
+\&
+ printf("Listening for events.\en");
+\&
+ /* Read events from the event queue into a buffer. */
+\&
+ len = read(fd, events_buf, sizeof(events_buf));
+ if (len == \-1 && errno != EAGAIN) {
+ perror("read");
+ exit(EXIT_FAILURE);
+ }
+\&
+ /* Process all events within the buffer. */
+\&
+ for (metadata = (struct fanotify_event_metadata *) events_buf;
+ FAN_EVENT_OK(metadata, len);
+ metadata = FAN_EVENT_NEXT(metadata, len)) {
+ fid = (struct fanotify_event_info_fid *) (metadata + 1);
+ file_handle = (struct file_handle *) fid\->handle;
+\&
+ /* Ensure that the event info is of the correct type. */
+\&
+ if (fid\->hdr.info_type == FAN_EVENT_INFO_TYPE_FID ||
+ fid\->hdr.info_type == FAN_EVENT_INFO_TYPE_DFID) {
+ file_name = NULL;
+ } else if (fid\->hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME) {
+ file_name = file_handle\->f_handle +
+ file_handle\->handle_bytes;
+ } else {
+ fprintf(stderr, "Received unexpected event info type.\en");
+ exit(EXIT_FAILURE);
+ }
+\&
+ if (metadata\->mask == FAN_CREATE)
+ printf("FAN_CREATE (file created):\en");
+\&
+ if (metadata\->mask == (FAN_CREATE | FAN_ONDIR))
+ printf("FAN_CREATE | FAN_ONDIR (subdirectory created):\en");
+\&
+ /* metadata\->fd is set to FAN_NOFD when the group identifies
+ objects by file handles. To obtain a file descriptor for
+ the file object corresponding to an event you can use the
+ struct file_handle that\[aq]s provided within the
+ fanotify_event_info_fid in conjunction with the
+ open_by_handle_at(2) system call. A check for ESTALE is
+ done to accommodate for the situation where the file handle
+ for the object was deleted prior to this system call. */
+\&
+ event_fd = open_by_handle_at(mount_fd, file_handle, O_RDONLY);
+ if (event_fd == \-1) {
+ if (errno == ESTALE) {
+ printf("File handle is no longer valid. "
+ "File has been deleted\en");
+ continue;
+ } else {
+ perror("open_by_handle_at");
+ exit(EXIT_FAILURE);
+ }
+ }
+\&
+ snprintf(procfd_path, sizeof(procfd_path), "/proc/self/fd/%d",
+ event_fd);
+\&
+ /* Retrieve and print the path of the modified dentry. */
+\&
+ path_len = readlink(procfd_path, path, sizeof(path) \- 1);
+ if (path_len == \-1) {
+ perror("readlink");
+ exit(EXIT_FAILURE);
+ }
+\&
+ path[path_len] = \[aq]\e0\[aq];
+ printf("\etDirectory \[aq]%s\[aq] has been modified.\en", path);
+\&
+ if (file_name) {
+ ret = fstatat(event_fd, file_name, &sb, 0);
+ if (ret == \-1) {
+ if (errno != ENOENT) {
+ perror("fstatat");
+ exit(EXIT_FAILURE);
+ }
+ printf("\etEntry \[aq]%s\[aq] does not exist.\en", file_name);
+ } else if ((sb.st_mode & S_IFMT) == S_IFDIR) {
+ printf("\etEntry \[aq]%s\[aq] is a subdirectory.\en", file_name);
+ } else {
+ printf("\etEntry \[aq]%s\[aq] is not a subdirectory.\en",
+ file_name);
+ }
+ }
+\&
+ /* Close associated file descriptor for this event. */
+\&
+ close(event_fd);
+ }
+\&
+ printf("All events processed successfully. Program exiting.\en");
+ exit(EXIT_SUCCESS);
+}
+.EE
+.SH SEE ALSO
+.ad l
+.BR fanotify_init (2),
+.BR fanotify_mark (2),
+.BR inotify (7)