diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-24 04:52:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-24 04:52:22 +0000 |
commit | 3d08cd331c1adcf0d917392f7e527b3f00511748 (patch) | |
tree | 312f0d1e1632f48862f044b8bb87e602dcffb5f9 /man/man7/fanotify.7 | |
parent | Adding debian version 6.7-2. (diff) | |
download | manpages-3d08cd331c1adcf0d917392f7e527b3f00511748.tar.xz manpages-3d08cd331c1adcf0d917392f7e527b3f00511748.zip |
Merging upstream version 6.8.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'man/man7/fanotify.7')
-rw-r--r-- | man/man7/fanotify.7 | 1456 |
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) |