1440 lines
53 KiB
HTML
1440 lines
53 KiB
HTML
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<HTML><HEAD><TITLE>Man page of FANOTIFY</TITLE>
|
|
</HEAD><BODY>
|
|
<H1>FANOTIFY</H1>
|
|
Section: Linux Programmer's Manual (7)<BR>Updated: 2019-08-02<BR><A HREF="#index">Index</A>
|
|
<A HREF="/cgi-bin/man/man2html">Return to Main Contents</A><HR>
|
|
|
|
<A NAME="lbAB"> </A>
|
|
<H2>NAME</H2>
|
|
|
|
fanotify - monitoring filesystem events
|
|
<A NAME="lbAC"> </A>
|
|
<H2>DESCRIPTION</H2>
|
|
|
|
The fanotify API provides notification and interception of
|
|
filesystem events.
|
|
Use cases include virus scanning and hierarchical storage management.
|
|
Currently, only a limited set of events is supported.
|
|
In particular, there is no support for create, delete, and move events.
|
|
(See
|
|
<B><A HREF="/cgi-bin/man/man2html?7+inotify">inotify</A></B>(7)
|
|
|
|
for details of an API that does notify those events.)
|
|
<P>
|
|
|
|
Additional capabilities compared to the
|
|
<B><A HREF="/cgi-bin/man/man2html?7+inotify">inotify</A></B>(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:
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_mark">fanotify_mark</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+write">write</A></B>(2),
|
|
|
|
and
|
|
<B><A HREF="/cgi-bin/man/man2html?2+close">close</A></B>(2).
|
|
|
|
<A NAME="lbAD"> </A>
|
|
<H3>fanotify_init(), fanotify_mark(), and notification groups</H3>
|
|
|
|
The
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(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 mount points for which
|
|
events shall be created.
|
|
<P>
|
|
|
|
For each entry in an fanotify notification group, two bit masks exist: the
|
|
<I>mark</I>
|
|
|
|
mask and the
|
|
<I>ignore</I>
|
|
|
|
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 point, or
|
|
directory to be marked for receiving events, while at the same time
|
|
ignoring events for specific objects under a mount point or directory.
|
|
<P>
|
|
|
|
The
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_mark">fanotify_mark</A></B>(2)
|
|
|
|
system call adds a file, directory, filesystem or mount point 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 point 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.
|
|
<A NAME="lbAE"> </A>
|
|
<H3>The event queue</H3>
|
|
|
|
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
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2)
|
|
|
|
or similar)
|
|
from the fanotify file descriptor
|
|
returned by
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(2).
|
|
|
|
<P>
|
|
|
|
Two types of events are generated:
|
|
<I>notification</I>
|
|
|
|
events and
|
|
<I>permission</I>
|
|
|
|
events.
|
|
Notification events are merely informative
|
|
and require no action to be taken by
|
|
the receiving application with the exception being that the file
|
|
descriptor provided within a generic event must be closed.
|
|
The closing of file descriptors for each event applies only to
|
|
applications that have initialized fanotify without using
|
|
<B>FAN_REPORT_FID</B>
|
|
|
|
(see below).
|
|
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.
|
|
<A NAME="lbAF"> </A>
|
|
<H3>Reading fanotify events</H3>
|
|
|
|
Calling
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2)
|
|
|
|
for the file descriptor returned by
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(2)
|
|
|
|
blocks (if the flag
|
|
<B>FAN_NONBLOCK</B>
|
|
|
|
is not specified in the call to
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(2))
|
|
|
|
until either a file event occurs or the call is interrupted by a signal
|
|
(see
|
|
<B><A HREF="/cgi-bin/man/man2html?7+signal">signal</A></B>(7)).
|
|
|
|
<P>
|
|
|
|
The use of the
|
|
<B>FAN_REPORT_FID</B>
|
|
|
|
flag in
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(2)
|
|
|
|
influences what data structures are returned to the event listener for each
|
|
event.
|
|
After a successful
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2),
|
|
|
|
the read buffer contains one or more of the following structures:
|
|
<P>
|
|
|
|
|
|
|
|
struct fanotify_event_metadata {
|
|
<BR> __u32 event_len;
|
|
<BR> __u8 vers;
|
|
<BR> __u8 reserved;
|
|
<BR> __u16 metadata_len;
|
|
<BR> __aligned_u64 mask;
|
|
<BR> __s32 fd;
|
|
<BR> __s32 pid;
|
|
};
|
|
|
|
|
|
<P>
|
|
|
|
In the case where
|
|
<B>FAN_REPORT_FID</B>
|
|
|
|
is supplied as one of the flags to
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(2),
|
|
|
|
you should also expect to receive the structure detailed below following
|
|
the generic
|
|
<I>fanotify_event_metadata</I>
|
|
|
|
structure within the read buffer:
|
|
<P>
|
|
|
|
|
|
|
|
struct fanotify_event_info_fid {
|
|
<BR> struct fanotify_event_info_header hdr;
|
|
<BR> __kernel_fsid_t fsid;
|
|
<BR> unsigned char file_handle[0];
|
|
};
|
|
|
|
|
|
<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
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2).
|
|
|
|
<P>
|
|
|
|
The return value of
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(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</I>
|
|
|
|
structure are as follows:
|
|
<DL COMPACT>
|
|
<DT id="1"><I>event_len</I>
|
|
|
|
<DD>
|
|
This is the length of the data for the current event and the offset
|
|
to the next event in the buffer.
|
|
Without
|
|
<B>FAN_REPORT_FID</B>,
|
|
|
|
the value of
|
|
<I>event_len</I>
|
|
|
|
is always
|
|
<B>FAN_EVENT_METADATA_LEN</B>.
|
|
|
|
With
|
|
<B>FAN_REPORT_FID</B>,
|
|
|
|
<I>event_len</I>
|
|
|
|
also includes the variable length file identifier.
|
|
<DT id="2"><I>vers</I>
|
|
|
|
<DD>
|
|
This field holds a version number for the structure.
|
|
It must be compared to
|
|
<B>FANOTIFY_METADATA_VERSION</B>
|
|
|
|
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.
|
|
<DT id="3"><I>reserved</I>
|
|
|
|
<DD>
|
|
This field is not used.
|
|
<DT id="4"><I>metadata_len</I>
|
|
|
|
<DD>
|
|
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.
|
|
<DT id="5"><I>mask</I>
|
|
|
|
<DD>
|
|
This is a bit mask describing the event (see below).
|
|
<DT id="6"><I>fd</I>
|
|
|
|
<DD>
|
|
This is an open file descriptor for the object being accessed, or
|
|
<B>FAN_NOFD</B>
|
|
|
|
if a queue overflow occurred.
|
|
If the fanotify file descriptor has been initialized using
|
|
<B>FAN_REPORT_FID</B>,
|
|
|
|
applications should expect this value to be set to
|
|
<B>FAN_NOFD</B>
|
|
|
|
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.
|
|
<DT id="7"><DD>
|
|
When calling
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(2),
|
|
|
|
the caller may specify (via the
|
|
<I>event_f_flags</I>
|
|
|
|
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</B>
|
|
|
|
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.
|
|
<DT id="8"><I>pid</I>
|
|
|
|
<DD>
|
|
If flag
|
|
<B>FAN_REPORT_TID</B>
|
|
|
|
was set in
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(2),
|
|
|
|
this is the TID of the thread that caused the event.
|
|
Otherwise, this the PID of the process that caused the event.
|
|
</DL>
|
|
<P>
|
|
|
|
A program listening to fanotify events can compare this PID
|
|
to the PID returned by
|
|
<B><A HREF="/cgi-bin/man/man2html?2+getpid">getpid</A></B>(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</I>
|
|
|
|
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</I>
|
|
|
|
are as follows:
|
|
<DL COMPACT>
|
|
<DT id="9"><B>FAN_ACCESS</B>
|
|
|
|
<DD>
|
|
A file or a directory (but see BUGS) was accessed (read).
|
|
<DT id="10"><B>FAN_OPEN</B>
|
|
|
|
<DD>
|
|
A file or a directory was opened.
|
|
<DT id="11"><B>FAN_OPEN_EXEC</B>
|
|
|
|
<DD>
|
|
A file was opened with the intent to be executed.
|
|
See NOTES in
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_mark">fanotify_mark</A></B>(2)
|
|
|
|
for additional details.
|
|
<DT id="12"><B>FAN_ATTRIB</B>
|
|
|
|
<DD>
|
|
A file or directory metadata was changed.
|
|
<DT id="13"><B>FAN_CREATE</B>
|
|
|
|
<DD>
|
|
A child file or directory was created in a watched parent.
|
|
<DT id="14"><B>FAN_DELETE</B>
|
|
|
|
<DD>
|
|
A child file or directory was deleted in a watched parent.
|
|
<DT id="15"><B>FAN_DELETE_SELF</B>
|
|
|
|
<DD>
|
|
A watched file or directory was deleted.
|
|
<DT id="16"><B>FAN_MOVED_FROM</B>
|
|
|
|
<DD>
|
|
A file or directory has been moved from a watched parent directory.
|
|
<DT id="17"><B>FAN_MOVED_TO</B>
|
|
|
|
<DD>
|
|
A file or directory has been moved to a watched parent directory.
|
|
<DT id="18"><B>FAN_MOVE_SELF</B>
|
|
|
|
<DD>
|
|
A watched file or directory was moved.
|
|
<DT id="19"><B>FAN_MODIFY</B>
|
|
|
|
<DD>
|
|
A file was modified.
|
|
<DT id="20"><B>FAN_CLOSE_WRITE</B>
|
|
|
|
<DD>
|
|
A file that was opened for writing
|
|
(<B>O_WRONLY</B>
|
|
|
|
or
|
|
<B>O_RDWR</B>)
|
|
|
|
was closed.
|
|
<DT id="21"><B>FAN_CLOSE_NOWRITE</B>
|
|
|
|
<DD>
|
|
A file or directory that was opened read-only
|
|
(<B>O_RDONLY</B>)
|
|
|
|
was closed.
|
|
<DT id="22"><B>FAN_Q_OVERFLOW</B>
|
|
|
|
<DD>
|
|
The event queue exceeded the limit of 16384 entries.
|
|
This limit can be overridden by specifying the
|
|
<B>FAN_UNLIMITED_QUEUE</B>
|
|
|
|
flag when calling
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(2).
|
|
|
|
<DT id="23"><B>FAN_ACCESS_PERM</B>
|
|
|
|
<DD>
|
|
An application wants to read a file or directory, for example using
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2)
|
|
|
|
or
|
|
<B><A HREF="/cgi-bin/man/man2html?2+readdir">readdir</A></B>(2).
|
|
|
|
The reader must write a response (as described below)
|
|
that determines whether the permission to
|
|
access the filesystem object shall be granted.
|
|
<DT id="24"><B>FAN_OPEN_PERM</B>
|
|
|
|
<DD>
|
|
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.
|
|
<DT id="25"><B>FAN_OPEN_EXEC_PERM</B>
|
|
|
|
<DD>
|
|
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
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_mark">fanotify_mark</A></B>(2)
|
|
|
|
for additional details.
|
|
</DL>
|
|
<P>
|
|
|
|
To check for any close event, the following bit mask may be used:
|
|
<DL COMPACT>
|
|
<DT id="26"><B>FAN_CLOSE</B>
|
|
|
|
<DD>
|
|
A file was closed.
|
|
This is a synonym for:
|
|
<DT id="27"><DD>
|
|
<BR> FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE
|
|
</DL>
|
|
<P>
|
|
|
|
To check for any move event, the following bit mask may be used:
|
|
<DL COMPACT>
|
|
<DT id="28"><B>FAN_MOVE</B>
|
|
|
|
<DD>
|
|
A file or directory was moved.
|
|
This is a synonym for:
|
|
<DT id="29"><DD>
|
|
<BR> FAN_MOVED_FROM | FAN_MOVED_TO
|
|
</DL>
|
|
<P>
|
|
|
|
The fields of the
|
|
<I>fanotify_event_info_fid</I>
|
|
|
|
structure are as follows:
|
|
<DL COMPACT>
|
|
<DT id="30"><I>hdr</I>
|
|
|
|
<DD>
|
|
This is a structure of type
|
|
<I>fanotify_event_info_header</I>.
|
|
|
|
It is a generic header that contains information used to describe
|
|
additional information attached to the event.
|
|
For example, when an fanotify file descriptor is created using
|
|
<B>FAN_REPORT_FID</B>,
|
|
|
|
the
|
|
<I>info_type</I>
|
|
|
|
field of this header is set to
|
|
<B>FAN_EVENT_INFO_TYPE_FID</B>.
|
|
|
|
Event listeners can use this field to check that the additional
|
|
information received for an event is of the correct type.
|
|
Additionally, the
|
|
<I>fanotify_event_info_header</I>
|
|
|
|
also contains a
|
|
<I>len</I>
|
|
|
|
field.
|
|
In the current implementation, the value of
|
|
<I>len</I>
|
|
|
|
is always (event_len - FAN_EVENT_METADATA_LEN).
|
|
<DT id="31"><I>fsid</I>
|
|
|
|
<DD>
|
|
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</I>
|
|
|
|
and contains the same value as
|
|
<I>f_fsid</I>
|
|
|
|
when calling
|
|
<B><A HREF="/cgi-bin/man/man2html?2+statfs">statfs</A></B>(2).
|
|
|
|
<DT id="32"><I>file_handle</I>
|
|
|
|
<DD>
|
|
This is a variable length structure of type
|
|
<I>file_handle</I>.
|
|
|
|
It is an opaque handle that corresponds to a specified object on a
|
|
filesystem as returned by
|
|
<B><A HREF="/cgi-bin/man/man2html?2+name_to_handle_at">name_to_handle_at</A></B>(2).
|
|
|
|
It can be used to uniquely identify a file on a filesystem and can be
|
|
passed as an argument to
|
|
<B><A HREF="/cgi-bin/man/man2html?2+open_by_handle_at">open_by_handle_at</A></B>(2).
|
|
|
|
Note that for directory entry events, such as
|
|
<B>FAN_CREATE</B>,
|
|
|
|
<B>FAN_DELETE</B>,
|
|
|
|
and
|
|
<B>FAN_MOVE</B>,
|
|
|
|
the
|
|
<I>file_handle</I>
|
|
|
|
describes the modified directory and not the created/deleted/moved child
|
|
object.
|
|
The events
|
|
<B>FAN_ATTRIB</B>,
|
|
|
|
<B>FAN_DELETE_SELF</B>,
|
|
|
|
and
|
|
<B>FAN_MOVE_SELF</B>
|
|
|
|
will carry the
|
|
<I>file_handle</I>
|
|
|
|
information for the child object if the child object is being watched.
|
|
</DL>
|
|
<P>
|
|
|
|
The following macros are provided to iterate over a buffer containing
|
|
fanotify event metadata returned by a
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2)
|
|
|
|
from an fanotify file descriptor:
|
|
<DL COMPACT>
|
|
<DT id="33"><B>FAN_EVENT_OK(meta, len)</B>
|
|
|
|
<DD>
|
|
This macro checks the remaining length
|
|
<I>len</I>
|
|
|
|
of the buffer
|
|
<I>meta</I>
|
|
|
|
against the length of the metadata structure and the
|
|
<I>event_len</I>
|
|
|
|
field of the first metadata structure in the buffer.
|
|
<DT id="34"><B>FAN_EVENT_NEXT(meta, len)</B>
|
|
|
|
<DD>
|
|
This macro uses the length indicated in the
|
|
<I>event_len</I>
|
|
|
|
field of the metadata structure pointed to by
|
|
<I>meta</I>
|
|
|
|
to calculate the address of the next metadata structure that follows
|
|
<I>meta</I>.
|
|
|
|
<I>len</I>
|
|
|
|
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
|
|
<I>meta</I>,
|
|
|
|
and reduces
|
|
<I>len</I>
|
|
|
|
by the number of bytes in the metadata structure that
|
|
has been skipped over (i.e., it subtracts
|
|
<I>meta->event_len</I>
|
|
|
|
from
|
|
<I>len</I>).
|
|
|
|
</DL>
|
|
<P>
|
|
|
|
In addition, there is:
|
|
<DL COMPACT>
|
|
<DT id="35"><B>FAN_EVENT_METADATA_LEN</B>
|
|
|
|
<DD>
|
|
This macro returns the size (in bytes) of the structure
|
|
<I>fanotify_event_metadata</I>.
|
|
|
|
This is the minimum size (and currently the only size) of any event metadata.
|
|
|
|
</DL>
|
|
<A NAME="lbAG"> </A>
|
|
<H3>Monitoring an fanotify file descriptor for events</H3>
|
|
|
|
When an fanotify event occurs, the fanotify file descriptor indicates as
|
|
readable when passed to
|
|
<B><A HREF="/cgi-bin/man/man2html?7+epoll">epoll</A></B>(7),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+poll">poll</A></B>(2),
|
|
|
|
or
|
|
<B><A HREF="/cgi-bin/man/man2html?2+select">select</A></B>(2).
|
|
|
|
<A NAME="lbAH"> </A>
|
|
<H3>Dealing with permission events</H3>
|
|
|
|
For permission events, the application must
|
|
<B><A HREF="/cgi-bin/man/man2html?2+write">write</A></B>(2)
|
|
|
|
a structure of the following form to the
|
|
fanotify file descriptor:
|
|
<P>
|
|
|
|
|
|
|
|
struct fanotify_response {
|
|
<BR> __s32 fd;
|
|
<BR> __u32 response;
|
|
};
|
|
|
|
|
|
<P>
|
|
|
|
The fields of this structure are as follows:
|
|
<DL COMPACT>
|
|
<DT id="36"><I>fd</I>
|
|
|
|
<DD>
|
|
This is the file descriptor from the structure
|
|
<I>fanotify_event_metadata</I>.
|
|
|
|
<DT id="37"><I>response</I>
|
|
|
|
<DD>
|
|
This field indicates whether or not the permission is to be granted.
|
|
Its value must be either
|
|
<B>FAN_ALLOW</B>
|
|
|
|
to allow the file operation or
|
|
<B>FAN_DENY</B>
|
|
|
|
to deny the file operation.
|
|
</DL>
|
|
<P>
|
|
|
|
If access is denied, the requesting application call will receive an
|
|
<B>EPERM</B>
|
|
|
|
error.
|
|
<A NAME="lbAI"> </A>
|
|
<H3>Closing the fanotify file descriptor</H3>
|
|
|
|
<P>
|
|
|
|
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
|
|
<B><A HREF="/cgi-bin/man/man2html?2+close">close</A></B>(2),
|
|
|
|
outstanding permission events will be set to allowed.
|
|
<A NAME="lbAJ"> </A>
|
|
<H3>/proc/[pid]/fdinfo</H3>
|
|
|
|
The file
|
|
<I>/proc/[pid]/fdinfo/[fd]</I>
|
|
|
|
contains information about fanotify marks for file descriptor
|
|
<I>fd</I>
|
|
|
|
of process
|
|
<I>pid</I>.
|
|
|
|
See
|
|
<B><A HREF="/cgi-bin/man/man2html?5+proc">proc</A></B>(5)
|
|
|
|
for details.
|
|
<A NAME="lbAK"> </A>
|
|
<H2>ERRORS</H2>
|
|
|
|
In addition to the usual errors for
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2),
|
|
|
|
the following errors can occur when reading from the
|
|
fanotify file descriptor:
|
|
<DL COMPACT>
|
|
<DT id="38"><B>EINVAL</B>
|
|
|
|
<DD>
|
|
The buffer is too small to hold the event.
|
|
<DT id="39"><B>EMFILE</B>
|
|
|
|
<DD>
|
|
The per-process limit on the number of open files has been reached.
|
|
See the description of
|
|
<B>RLIMIT_NOFILE</B>
|
|
|
|
in
|
|
<B><A HREF="/cgi-bin/man/man2html?2+getrlimit">getrlimit</A></B>(2).
|
|
|
|
<DT id="40"><B>ENFILE</B>
|
|
|
|
<DD>
|
|
The system-wide limit on the total number of open files has been reached.
|
|
See
|
|
<I>/proc/sys/fs/file-max</I>
|
|
|
|
in
|
|
<B><A HREF="/cgi-bin/man/man2html?5+proc">proc</A></B>(5).
|
|
|
|
<DT id="41"><B>ETXTBSY</B>
|
|
|
|
<DD>
|
|
This error is returned by
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(2)
|
|
|
|
if
|
|
<B>O_RDWR</B>
|
|
|
|
or
|
|
<B>O_WRONLY</B>
|
|
|
|
was specified in the
|
|
<I>event_f_flags</I>
|
|
|
|
argument when calling
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(2)
|
|
|
|
and an event occurred for a monitored file that is currently being executed.
|
|
</DL>
|
|
<P>
|
|
|
|
In addition to the usual errors for
|
|
<B><A HREF="/cgi-bin/man/man2html?2+write">write</A></B>(2),
|
|
|
|
the following errors can occur when writing to the fanotify file descriptor:
|
|
<DL COMPACT>
|
|
<DT id="42"><B>EINVAL</B>
|
|
|
|
<DD>
|
|
Fanotify access permissions are not enabled in the kernel configuration
|
|
or the value of
|
|
<I>response</I>
|
|
|
|
in the response structure is not valid.
|
|
<DT id="43"><B>ENOENT</B>
|
|
|
|
<DD>
|
|
The file descriptor
|
|
<I>fd</I>
|
|
|
|
in the response structure is not valid.
|
|
This may occur when a response for the permission event has already been
|
|
written.
|
|
</DL>
|
|
<A NAME="lbAL"> </A>
|
|
<H2>VERSIONS</H2>
|
|
|
|
The fanotify API was introduced in version 2.6.36 of the Linux kernel and
|
|
enabled in version 2.6.37.
|
|
Fdinfo support was added in version 3.8.
|
|
<A NAME="lbAM"> </A>
|
|
<H2>CONFORMING TO</H2>
|
|
|
|
The fanotify API is Linux-specific.
|
|
<A NAME="lbAN"> </A>
|
|
<H2>NOTES</H2>
|
|
|
|
The fanotify API is available only if the kernel was built with the
|
|
<B>CONFIG_FANOTIFY</B>
|
|
|
|
configuration option enabled.
|
|
In addition, fanotify permission handling is available only if the
|
|
<B>CONFIG_FANOTIFY_ACCESS_PERMISSIONS</B>
|
|
|
|
configuration option is enabled.
|
|
<A NAME="lbAO"> </A>
|
|
<H3>Limitations and caveats</H3>
|
|
|
|
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
|
|
<B><A HREF="/cgi-bin/man/man2html?2+mmap">mmap</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+msync">msync</A></B>(2),
|
|
|
|
and
|
|
<B><A HREF="/cgi-bin/man/man2html?2+munmap">munmap</A></B>(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.
|
|
(But note that the fanotify API provides no way of detecting when a
|
|
subdirectory has been created under a marked directory,
|
|
which makes recursive monitoring difficult.)
|
|
Monitoring mounts offers the capability to monitor a whole directory tree.
|
|
Monitoring filesystems offers the capability to monitor changes made from
|
|
any mount of a filesystem instance.
|
|
<P>
|
|
|
|
The event queue can overflow.
|
|
In this case, events are lost.
|
|
<A NAME="lbAP"> </A>
|
|
<H2>BUGS</H2>
|
|
|
|
Before Linux 3.19,
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fallocate">fallocate</A></B>(2)
|
|
|
|
did not generate fanotify events.
|
|
Since Linux 3.19,
|
|
|
|
calls to
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fallocate">fallocate</A></B>(2)
|
|
|
|
generate
|
|
<B>FAN_MODIFY</B>
|
|
|
|
events.
|
|
<P>
|
|
|
|
As of Linux 3.17,
|
|
the following bugs exist:
|
|
<DL COMPACT>
|
|
<DT id="44">*<DD>
|
|
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</I>
|
|
|
|
option of
|
|
<B><A HREF="/cgi-bin/man/man2html?8+mount">mount</A></B>(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.
|
|
<DT id="45">*<DD>
|
|
|
|
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</B>
|
|
|
|
capability is set for programs executed by unprivileged users.
|
|
<DT id="46">*<DD>
|
|
If a call to
|
|
<B><A HREF="/cgi-bin/man/man2html?2+read">read</A></B>(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</I>
|
|
|
|
will not be set.
|
|
Thus, the reading application has no way to detect the error.
|
|
</DL>
|
|
<A NAME="lbAQ"> </A>
|
|
<H2>EXAMPLE</H2>
|
|
|
|
The two example programs below demonstrate the usage of the fanotify API.
|
|
<A NAME="lbAR"> </A>
|
|
<H3>Example program: fanotify_example.c</H3>
|
|
|
|
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 point passed as a command-line argument and
|
|
waits for events of type
|
|
<B>FAN_OPEN_PERM</B>
|
|
|
|
and
|
|
<B>FAN_CLOSE_WRITE</B>.
|
|
|
|
When a permission event occurs, a
|
|
<B>FAN_ALLOW</B>
|
|
|
|
response is given.
|
|
<P>
|
|
|
|
The following shell session shows an example of
|
|
running this program.
|
|
This session involved editing the file
|
|
<I>/home/user/temp/notes</I>.
|
|
|
|
Before the file was opened, a
|
|
<B>FAN_OPEN_PERM</B>
|
|
|
|
event occurred.
|
|
After the file was closed, a
|
|
<B>FAN_CLOSE_WRITE</B>
|
|
|
|
event occurred.
|
|
Execution of the program ends when the user presses the ENTER key.
|
|
<P>
|
|
|
|
|
|
|
|
# <B>./fanotify_example /home</B>
|
|
Press enter key to terminate.
|
|
Listening for events.
|
|
FAN_OPEN_PERM: File /home/user/temp/notes
|
|
FAN_CLOSE_WRITE: File /home/user/temp/notes
|
|
<P>
|
|
Listening for events stopped.
|
|
|
|
|
|
<A NAME="lbAS"> </A>
|
|
<H3>Program source: fanotify_example.c</H3>
|
|
|
|
|
|
|
|
#define _GNU_SOURCE /* Needed to get O_LARGEFILE definition */
|
|
#include <<A HREF="file:///usr/include/errno.h">errno.h</A>>
|
|
#include <<A HREF="file:///usr/include/fcntl.h">fcntl.h</A>>
|
|
#include <<A HREF="file:///usr/include/limits.h">limits.h</A>>
|
|
#include <<A HREF="file:///usr/include/poll.h">poll.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdio.h">stdio.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdlib.h">stdlib.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/fanotify.h">sys/fanotify.h</A>>
|
|
#include <<A HREF="file:///usr/include/unistd.h">unistd.h</A>>
|
|
<P>
|
|
/* Read all available fanotify events from the file descriptor 'fd' */
|
|
<P>
|
|
static void
|
|
handle_events(int fd)
|
|
{
|
|
<BR> const struct fanotify_event_metadata *metadata;
|
|
<BR> struct fanotify_event_metadata buf[200];
|
|
<BR> ssize_t len;
|
|
<BR> char path[PATH_MAX];
|
|
<BR> ssize_t path_len;
|
|
<BR> char procfd_path[PATH_MAX];
|
|
<BR> struct fanotify_response response;
|
|
<P>
|
|
<BR> /* Loop while events can be read from fanotify file descriptor */
|
|
<P>
|
|
<BR> for (;;) {
|
|
<P>
|
|
<BR> /* Read some events */
|
|
<P>
|
|
<BR> len = read(fd, (void *) &buf, sizeof(buf));
|
|
<BR> if (len == -1 && errno != EAGAIN) {
|
|
<BR> perror("read");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Check if end of available data reached */
|
|
<P>
|
|
<BR> if (len <= 0)
|
|
<BR> break;
|
|
<P>
|
|
<BR> /* Point to the first event in the buffer */
|
|
<P>
|
|
<BR> metadata = buf;
|
|
<P>
|
|
<BR> /* Loop over all events in the buffer */
|
|
<P>
|
|
<BR> while (FAN_EVENT_OK(metadata, len)) {
|
|
<P>
|
|
<BR> /* Check that run-time and compile-time structures match */
|
|
<P>
|
|
<BR> if (metadata->vers != FANOTIFY_METADATA_VERSION) {
|
|
<BR> fprintf(stderr,
|
|
<BR> "Mismatch of fanotify metadata version.\n");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* metadata->fd contains either FAN_NOFD, indicating a
|
|
<BR> queue overflow, or a file descriptor (a nonnegative
|
|
<BR> integer). Here, we simply ignore queue overflow. */
|
|
<P>
|
|
<BR> if (metadata->fd >= 0) {
|
|
<P>
|
|
<BR> /* Handle open permission event */
|
|
<P>
|
|
<BR> if (metadata->mask & FAN_OPEN_PERM) {
|
|
<BR> printf("FAN_OPEN_PERM: ");
|
|
<P>
|
|
<BR> /* Allow file to be opened */
|
|
<P>
|
|
<BR> response.fd = metadata->fd;
|
|
<BR> response.response = FAN_ALLOW;
|
|
<BR> write(fd, &response,
|
|
<BR> sizeof(struct fanotify_response));
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Handle closing of writable file event */
|
|
<P>
|
|
<BR> if (metadata->mask & FAN_CLOSE_WRITE)
|
|
<BR> printf("FAN_CLOSE_WRITE: ");
|
|
<P>
|
|
<BR> /* Retrieve and print pathname of the accessed file */
|
|
<P>
|
|
<BR> snprintf(procfd_path, sizeof(procfd_path),
|
|
<BR> "/proc/self/fd/%d", metadata->fd);
|
|
<BR> path_len = readlink(procfd_path, path,
|
|
<BR> sizeof(path) - 1);
|
|
<BR> if (path_len == -1) {
|
|
<BR> perror("readlink");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> path[path_len] = '\0';
|
|
<BR> printf("File %s\n", path);
|
|
<P>
|
|
<BR> /* Close the file descriptor of the event */
|
|
<P>
|
|
<BR> close(metadata->fd);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Advance to next event */
|
|
<P>
|
|
<BR> metadata = FAN_EVENT_NEXT(metadata, len);
|
|
<BR> }
|
|
<BR> }
|
|
}
|
|
<P>
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
<BR> char buf;
|
|
<BR> int fd, poll_num;
|
|
<BR> nfds_t nfds;
|
|
<BR> struct pollfd fds[2];
|
|
<P>
|
|
<BR> /* Check mount point is supplied */
|
|
<P>
|
|
<BR> if (argc != 2) {
|
|
<BR> fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> printf("Press enter key to terminate.\n");
|
|
<P>
|
|
<BR> /* Create the file descriptor for accessing the fanotify API */
|
|
<P>
|
|
<BR> fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
|
|
<BR> O_RDONLY | O_LARGEFILE);
|
|
<BR> if (fd == -1) {
|
|
<BR> perror("fanotify_init");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Mark the mount for:
|
|
<BR> - permission events before opening files
|
|
<BR> - notification events after closing a write-enabled
|
|
<BR> file descriptor */
|
|
<P>
|
|
<BR> if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
|
|
<BR> FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD,
|
|
<BR> argv[1]) == -1) {
|
|
<BR> perror("fanotify_mark");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Prepare for polling */
|
|
<P>
|
|
<BR> nfds = 2;
|
|
<P>
|
|
<BR> /* Console input */
|
|
<P>
|
|
<BR> fds[0].fd = STDIN_FILENO;
|
|
<BR> fds[0].events = POLLIN;
|
|
<P>
|
|
<BR> /* Fanotify input */
|
|
<P>
|
|
<BR> fds[1].fd = fd;
|
|
<BR> fds[1].events = POLLIN;
|
|
<P>
|
|
<BR> /* This is the loop to wait for incoming events */
|
|
<P>
|
|
<BR> printf("Listening for events.\n");
|
|
<P>
|
|
<BR> while (1) {
|
|
<BR> poll_num = poll(fds, nfds, -1);
|
|
<BR> if (poll_num == -1) {
|
|
<BR> if (errno == EINTR) /* Interrupted by a signal */
|
|
<BR> continue; /* Restart poll() */
|
|
<P>
|
|
<BR> perror("poll"); /* Unexpected error */
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> if (poll_num > 0) {
|
|
<BR> if (fds[0].revents & POLLIN) {
|
|
<P>
|
|
<BR> /* Console input is available: empty stdin and quit */
|
|
<P>
|
|
<BR> while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n')
|
|
<BR> continue;
|
|
<BR> break;
|
|
<BR> }
|
|
<P>
|
|
<BR> if (fds[1].revents & POLLIN) {
|
|
<P>
|
|
<BR> /* Fanotify events are available */
|
|
<P>
|
|
<BR> handle_events(fd);
|
|
<BR> }
|
|
<BR> }
|
|
<BR> }
|
|
<P>
|
|
<BR> printf("Listening for events stopped.\n");
|
|
<BR> exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
|
|
<A NAME="lbAT"> </A>
|
|
<H3>Example program: fanotify_fid.c</H3>
|
|
|
|
The second program is an example of fanotify being used with
|
|
<B>FAN_REPORT_FID</B>
|
|
|
|
enabled.
|
|
The program marks the filesystem object that is passed as
|
|
a command-line argument
|
|
and waits until an event of type
|
|
<B>FAN_CREATE</B>
|
|
|
|
has occurred.
|
|
The event mask indicates which type of filesystem object---either
|
|
a file or a directory---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
|
|
<I>/home/user</I>.
|
|
|
|
This is followed by the creation of a regular file,
|
|
<I>/home/user/testfile.txt</I>.
|
|
|
|
This results in a
|
|
<B>FAN_CREATE</B>
|
|
|
|
event being created and reported against the file's parent watched
|
|
directory object.
|
|
Program execution ends once all events captured within the buffer have
|
|
been processed.
|
|
Program execution ends once all events captured within the buffer are
|
|
processed.
|
|
<P>
|
|
|
|
|
|
|
|
# <B>./fanotify_fid /home/user</B>
|
|
Listening for events.
|
|
FAN_CREATE (file created): Directory /home/user has been modified.
|
|
All events processed successfully. Program exiting.
|
|
<P>
|
|
$ <B>touch /home/user/testing</B> # In another terminal
|
|
|
|
|
|
<P>
|
|
|
|
The second session shows a mark being placed on
|
|
<I>/home/user</I>.
|
|
|
|
This is followed by the creation of a directory,
|
|
<I>/home/user/testdir</I>.
|
|
|
|
This specific action results in the program producing a
|
|
<B>FAN_CREATE</B>
|
|
|
|
and
|
|
<B>FAN_ONDIR</B>
|
|
|
|
event.
|
|
<P>
|
|
|
|
|
|
|
|
# <B>./fanotify_fid /home/user</B>
|
|
Listening for events.
|
|
FAN_CREATE | FAN_ONDIR (subdirectory created):
|
|
<BR> Directory /home/user has been modified.
|
|
All events processed successfully. Program exiting.
|
|
<P>
|
|
$ <B>mkdir -p /home/user/testing</B> # In another terminal
|
|
|
|
|
|
<A NAME="lbAU"> </A>
|
|
<H3>Program source: fanotify_fid.c</H3>
|
|
|
|
|
|
|
|
#define _GNU_SOURCE
|
|
#include <<A HREF="file:///usr/include/errno.h">errno.h</A>>
|
|
#include <<A HREF="file:///usr/include/fcntl.h">fcntl.h</A>>
|
|
#include <<A HREF="file:///usr/include/limits.h">limits.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdio.h">stdio.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdlib.h">stdlib.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/types.h">sys/types.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/stat.h">sys/stat.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/fanotify.h">sys/fanotify.h</A>>
|
|
#include <<A HREF="file:///usr/include/unistd.h">unistd.h</A>>
|
|
<P>
|
|
#define BUF_SIZE 256
|
|
<P>
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
<BR> int fd, ret, event_fd;
|
|
<BR> ssize_t len, path_len;
|
|
<BR> char path[PATH_MAX];
|
|
<BR> char procfd_path[PATH_MAX];
|
|
<BR> char events_buf[BUF_SIZE];
|
|
<BR> struct file_handle *file_handle;
|
|
<BR> struct fanotify_event_metadata *metadata;
|
|
<BR> struct fanotify_event_info_fid *fid;
|
|
<P>
|
|
<BR> if (argc != 2) {
|
|
<BR> fprintf(stderr, "Invalid number of command line arguments.\n");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Create an fanotify file descriptor with FAN_REPORT_FID as a flag
|
|
<BR> so that program can receive fid events. */
|
|
<P>
|
|
<BR> fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_FID, 0);
|
|
<BR> if (fd == -1) {
|
|
<BR> perror("fanotify_init");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Place a mark on the filesystem object supplied in argv[1]. */
|
|
<P>
|
|
<BR> ret = fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_ONLYDIR,
|
|
<BR> FAN_CREATE | FAN_ONDIR,
|
|
<BR> AT_FDCWD, argv[1]);
|
|
<BR> if (ret == -1) {
|
|
<BR> perror("fanotify_mark");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> printf("Listening for events.\n");
|
|
<P>
|
|
<BR> /* Read events from the event queue into a buffer */
|
|
<P>
|
|
<BR> len = read(fd, (void *) &events_buf, sizeof(events_buf));
|
|
<BR> if (len == -1 && errno != EAGAIN) {
|
|
<BR> perror("read");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Process all events within the buffer */
|
|
<P>
|
|
<BR> for (metadata = (struct fanotify_event_metadata *) events_buf;
|
|
<BR> FAN_EVENT_OK(metadata, len);
|
|
<BR> metadata = FAN_EVENT_NEXT(metadata, len)) {
|
|
<BR> fid = (struct fanotify_event_info_fid *) (metadata + 1);
|
|
<BR> file_handle = (struct file_handle *) fid->handle;
|
|
<P>
|
|
<BR> /* Ensure that the event info is of the correct type */
|
|
<P>
|
|
<BR> if (fid->hdr.info_type != FAN_EVENT_INFO_TYPE_FID) {
|
|
<BR> fprintf(stderr, "Received unexpected event info type.\n");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> if (metadata->mask == FAN_CREATE)
|
|
<BR> printf("FAN_CREATE (file created):");
|
|
<P>
|
|
<BR> if (metadata->mask == FAN_CREATE | FAN_ONDIR)
|
|
<BR> printf("FAN_CREATE | FAN_ONDIR (subdirectory created):");
|
|
<P>
|
|
<BR> /* metadata->fd is set to FAN_NOFD when FAN_REPORT_FID is enabled.
|
|
<BR> To obtain a file descriptor for the file object corresponding to
|
|
<BR> an event you can use the struct file_handle that's provided
|
|
<BR> within the fanotify_event_info_fid in conjunction with the
|
|
<BR> <A HREF="/cgi-bin/man/man2html?2+open_by_handle_at">open_by_handle_at</A>(2) system call. A check for ESTALE is done
|
|
<BR> to accommodate for the situation where the file handle for the
|
|
<BR> object was deleted prior to this system call. */
|
|
<P>
|
|
<BR> event_fd = open_by_handle_at(AT_FDCWD, file_handle, O_RDONLY);
|
|
<BR> if (ret == -1) {
|
|
<BR> if (errno == ESTALE) {
|
|
<BR> printf("File handle is no longer valid. "
|
|
<BR> "File has been deleted\n");
|
|
<BR> continue;
|
|
<BR> } else {
|
|
<BR> perror("open_by_handle_at");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<TT> </TT> }<BR>
|
|
<BR> }
|
|
<P>
|
|
<BR> snprintf(procfd_path, sizeof(procfd_path), "/proc/self/fd/%d",
|
|
<BR> event_fd);
|
|
<P>
|
|
<BR> /* Retrieve and print the path of the modified dentry */
|
|
<P>
|
|
<BR> path_len = readlink(procfd_path, path, sizeof(path) - 1);
|
|
<BR> if (path_len == -1) {
|
|
<BR> perror("readlink");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> path[path_len] = '\0';
|
|
<BR> printf("\tDirectory '%s' has been modified.\n", path);
|
|
<P>
|
|
<BR> /* Close associated file descriptor for this event */
|
|
<P>
|
|
<BR> close(event_fd);
|
|
<BR> }
|
|
<P>
|
|
<BR> printf("All events processed successfully. Program exiting.\n");
|
|
<BR> exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
<A NAME="lbAV"> </A>
|
|
<H2>SEE ALSO</H2>
|
|
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_init">fanotify_init</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fanotify_mark">fanotify_mark</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?7+inotify">inotify</A></B>(7)
|
|
|
|
<A NAME="lbAW"> </A>
|
|
<H2>COLOPHON</H2>
|
|
|
|
This page is part of release 5.05 of the Linux
|
|
<I>man-pages</I>
|
|
|
|
project.
|
|
A description of the project,
|
|
information about reporting bugs,
|
|
and the latest version of this page,
|
|
can be found at
|
|
<A HREF="https://www.kernel.org/doc/man-pages/.">https://www.kernel.org/doc/man-pages/.</A>
|
|
<P>
|
|
|
|
<HR>
|
|
<A NAME="index"> </A><H2>Index</H2>
|
|
<DL>
|
|
<DT id="47"><A HREF="#lbAB">NAME</A><DD>
|
|
<DT id="48"><A HREF="#lbAC">DESCRIPTION</A><DD>
|
|
<DL>
|
|
<DT id="49"><A HREF="#lbAD">fanotify_init(), fanotify_mark(), and notification groups</A><DD>
|
|
<DT id="50"><A HREF="#lbAE">The event queue</A><DD>
|
|
<DT id="51"><A HREF="#lbAF">Reading fanotify events</A><DD>
|
|
<DT id="52"><A HREF="#lbAG">Monitoring an fanotify file descriptor for events</A><DD>
|
|
<DT id="53"><A HREF="#lbAH">Dealing with permission events</A><DD>
|
|
<DT id="54"><A HREF="#lbAI">Closing the fanotify file descriptor</A><DD>
|
|
<DT id="55"><A HREF="#lbAJ">/proc/[pid]/fdinfo</A><DD>
|
|
</DL>
|
|
<DT id="56"><A HREF="#lbAK">ERRORS</A><DD>
|
|
<DT id="57"><A HREF="#lbAL">VERSIONS</A><DD>
|
|
<DT id="58"><A HREF="#lbAM">CONFORMING TO</A><DD>
|
|
<DT id="59"><A HREF="#lbAN">NOTES</A><DD>
|
|
<DL>
|
|
<DT id="60"><A HREF="#lbAO">Limitations and caveats</A><DD>
|
|
</DL>
|
|
<DT id="61"><A HREF="#lbAP">BUGS</A><DD>
|
|
<DT id="62"><A HREF="#lbAQ">EXAMPLE</A><DD>
|
|
<DL>
|
|
<DT id="63"><A HREF="#lbAR">Example program: fanotify_example.c</A><DD>
|
|
<DT id="64"><A HREF="#lbAS">Program source: fanotify_example.c</A><DD>
|
|
<DT id="65"><A HREF="#lbAT">Example program: fanotify_fid.c</A><DD>
|
|
<DT id="66"><A HREF="#lbAU">Program source: fanotify_fid.c</A><DD>
|
|
</DL>
|
|
<DT id="67"><A HREF="#lbAV">SEE ALSO</A><DD>
|
|
<DT id="68"><A HREF="#lbAW">COLOPHON</A><DD>
|
|
</DL>
|
|
<HR>
|
|
This document was created by
|
|
<A HREF="/cgi-bin/man/man2html">man2html</A>,
|
|
using the manual pages.<BR>
|
|
Time: 00:06:08 GMT, March 31, 2021
|
|
</BODY>
|
|
</HTML>
|