mirror of https://github.com/mkerrisk/man-pages
fanotify.7: New page providing overview of the fanotify API
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
parent
a29edaeef6
commit
597aaea2f7
|
@ -0,0 +1,670 @@
|
|||
.\" Copyright (C) 2013, Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
.\"
|
||||
.\" %%%LICENSE_START(VERBATIM)
|
||||
.\" Permission is granted to make and distribute verbatim copies of this
|
||||
.\" manual provided the copyright notice and this permission notice are
|
||||
.\" preserved on all copies.
|
||||
.\"
|
||||
.\" Permission is granted to copy and distribute modified versions of
|
||||
.\" this manual under the conditions for verbatim copying, provided that
|
||||
.\" the entire resulting derived work is distributed under the terms of
|
||||
.\" a permission notice identical to this one.
|
||||
.\"
|
||||
.\" Since the Linux kernel and libraries are constantly changing, this
|
||||
.\" manual page may be incorrect or out-of-date. The author(s) assume.
|
||||
.\" no responsibility for errors or omissions, or for damages resulting.
|
||||
.\" from the use of the information contained herein. The author(s) may.
|
||||
.\" not have taken the same level of care in the production of this.
|
||||
.\" manual, which is licensed free of charge, as they might when working.
|
||||
.\" professionally.
|
||||
.\"
|
||||
.\" Formatted or processed versions of this manual, if unaccompanied by
|
||||
.\" the source, must acknowledge the copyright and authors of this work.
|
||||
.\" %%%LICENSE_END
|
||||
.TH FANOTIFY 7 2014-04-24 "Linux" "Linux Programmer's Manual"
|
||||
.SH NAME
|
||||
fanotify \- monitoring filesystem events
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B 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.
|
||||
|
||||
Additional capabilities compared to the
|
||||
.BR inotify (7)
|
||||
API are monitoring of complete mounts, access permission decisions, and the
|
||||
possibility to read or modify files before access by other applications.
|
||||
|
||||
The following system calls are used with this API:
|
||||
.BR fanotify_init (2),
|
||||
.BR fanotify_mark (2),
|
||||
.BR poll (2),
|
||||
.BR ppoll (2),
|
||||
.BR read (2),
|
||||
.BR write (2),
|
||||
and
|
||||
.BR close (2).
|
||||
.PP
|
||||
.BR fanotify_init (2)
|
||||
creates and initializes an fanotify notification group and returns a file
|
||||
descriptor referring to it.
|
||||
.PP
|
||||
An fanotify notification group is an internal object of the kernel which holds
|
||||
a list of files, directories, and mount points for which events shall be
|
||||
created.
|
||||
.PP
|
||||
For each entry in an fanotify notification group, two bit masks exist.
|
||||
One mask (the mark mask) defines file activities for which an event shall be
|
||||
created.
|
||||
Another mask (the ignore mask) defines activities for which no event shall be
|
||||
generated.
|
||||
Having these two types of masks permits a mount point or directory to be
|
||||
marked for receiving events, while at the same time ignoring events for
|
||||
specific objects under that mount point or directory.
|
||||
.PP
|
||||
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 closed event, the modify event can be removed from the
|
||||
ignore mask and the file cache entry can be updated.
|
||||
.PP
|
||||
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, the respective entries survive.
|
||||
If files or directories are deleted or mounts are unmounted, the corresponding
|
||||
entries are deleted.
|
||||
.PP
|
||||
Two types of events exist: notification events and permission events.
|
||||
Notification events are only informative and require no action to be taken by
|
||||
the receiving application except for closing the file descriptor passed in the
|
||||
event.
|
||||
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.
|
||||
.PP
|
||||
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.
|
||||
.PP
|
||||
.BR fanotify_mark (2)
|
||||
adds a file, directory, or mount to the group and specifies which events
|
||||
shall be reported (or ignored), or removes or modifies such an entry.
|
||||
.PP
|
||||
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).
|
||||
.PP
|
||||
All events for an fanotify group are collected in a queue.
|
||||
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.
|
||||
Queue entries for notification events are removed when the event has been
|
||||
read.
|
||||
Queue entries for permission events are removed when the permission
|
||||
decision has been taken by writing to the fanotify file descriptor.
|
||||
.PP
|
||||
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)).
|
||||
|
||||
The return value of
|
||||
.BR read (2)
|
||||
is the length of the filled buffer, or \-1 in case of an error.
|
||||
After a successful
|
||||
.BR read(2),
|
||||
the read buffer contains one or more of the following structures:
|
||||
|
||||
.in +4n
|
||||
.nf
|
||||
struct fanotify_event_metadata {
|
||||
__u32 event_len;
|
||||
__u8 vers;
|
||||
__u8 reserved;
|
||||
__u16 metadata_len;
|
||||
__aligned_u64 mask;
|
||||
__s32 fd;
|
||||
__s32 pid;
|
||||
};
|
||||
.fi
|
||||
.in
|
||||
|
||||
.TP 15
|
||||
.I event_len
|
||||
This is the length of the data for the current event and the offset to the next
|
||||
event in the buffer.
|
||||
In the current implementation the value of
|
||||
.I event_len
|
||||
is always
|
||||
.BR FAN_EVENT_METADATA_LEN .
|
||||
In principal the API design would allow to return variable length structures.
|
||||
Therefore, and for performance reasons, it is recommended to use a larger
|
||||
buffer size when reading, for example 4096 bytes.
|
||||
.TP
|
||||
.I vers
|
||||
This field holds a version number for the structures.
|
||||
It must be compared to
|
||||
.B FANOTIFY_METADATA_VERSION
|
||||
to verify that the structures at runtime match the structures 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.
|
||||
.TP
|
||||
.I fd
|
||||
This is an open file descriptor for the object being accessed, or
|
||||
.B FAN_NOFD
|
||||
if a queue overflow occurred.
|
||||
The file descriptor can be used to access the contents of the monitored file or
|
||||
directory.
|
||||
It has internal the flag
|
||||
.B FMODE_NONOTIFY
|
||||
set.
|
||||
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.
|
||||
The reading application is responsible for closing the file descriptor.
|
||||
.TP
|
||||
.I pid
|
||||
This is the ID of the process that caused the event.
|
||||
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 program.
|
||||
.PP
|
||||
The bit mask in
|
||||
.I mask
|
||||
signals which events have occurred for a single filesystem object.
|
||||
More than one of the following flags can be set at once in the bit mask.
|
||||
.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_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 that was only opened for reading
|
||||
.RB ( O_RDONLY )
|
||||
or a directory was closed.
|
||||
.TP
|
||||
.B FAN_Q_OVERFLOW
|
||||
The event queue exceeded the limit of 16384 entries.
|
||||
This limit can be overridden in the call to
|
||||
.BR fanotify_init (2)
|
||||
by setting the flag
|
||||
.BR FAN_UNLIMITED_QUEUE .
|
||||
.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 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.
|
||||
.PP
|
||||
To check for any close event, the following bit mask may be used:
|
||||
.TP
|
||||
.B FAN_CLOSE
|
||||
A file was closed
|
||||
(FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE).
|
||||
.PP
|
||||
The following macros are provided to iterate over a buffer containing fanotify
|
||||
event metadata returned by
|
||||
.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 sets the pointer
|
||||
.I meta
|
||||
to the next metadata structure using the length indicated in the
|
||||
.I event_len
|
||||
field of the metadata structure and reduces the remaining length of the
|
||||
buffer
|
||||
.IT len .
|
||||
.PP
|
||||
For permission events, the application must
|
||||
.BR write (2)
|
||||
a structure of the following form to the
|
||||
.B fanotify
|
||||
file descriptor:
|
||||
|
||||
.in +4n
|
||||
.nf
|
||||
struct fanotify_response {
|
||||
__s32 fd;
|
||||
__u32 response;
|
||||
};
|
||||
.fi
|
||||
.in
|
||||
|
||||
.TP 15
|
||||
.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.
|
||||
.PP
|
||||
If access has been denied, the requesting application call will receive an
|
||||
error
|
||||
.BR EPERM .
|
||||
.PP
|
||||
To end listening, it is sufficient to
|
||||
.BR close (2)
|
||||
the fanotify file descriptor.
|
||||
The outstanding permission events will be set to allowed, and all resources
|
||||
will be returned to the kernel.
|
||||
.PP
|
||||
The file
|
||||
.I /proc/<pid>/fdinfo/<fd>
|
||||
contains information about fanotify marks for file descriptor
|
||||
.I fd
|
||||
of process
|
||||
.IR pid .
|
||||
See
|
||||
.I Documentation/filesystems/proc.txt
|
||||
for details.
|
||||
.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 short 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 number of open files has been reached.
|
||||
See
|
||||
.I /proc/sys/fs/file-max
|
||||
in
|
||||
.BR proc (5).
|
||||
.TP
|
||||
.B ETXTBSY
|
||||
A write enabled file descriptor shall be created for a file that is executing.
|
||||
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 the event occured for a monitored file that is currently being execuded.
|
||||
.PP
|
||||
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 might occur because the file was already deleted by another thread or
|
||||
process.
|
||||
.SH VERSIONS
|
||||
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.
|
||||
.SH "CONFORMING TO"
|
||||
The fanotify API is Linux-specific.
|
||||
.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.
|
||||
.PP
|
||||
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).
|
||||
.PP
|
||||
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.
|
||||
.PP
|
||||
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.
|
||||
.PP
|
||||
The event queue can overflow.
|
||||
In this case, events are lost.
|
||||
.SH BUGS
|
||||
As of Linux 3.15,
|
||||
the following bugs existed:
|
||||
.IP * 3
|
||||
.\" FIXME: Patch is in linux-next-20140424.
|
||||
.BR readdir (2)
|
||||
does not create a
|
||||
.B FAN_ACCESS
|
||||
event.
|
||||
.IP *
|
||||
.\" 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 in
|
||||
This poses a security risk, when the
|
||||
.B CAP_SYS_ADMIN
|
||||
capability is set for programs executed by unprivileged users.
|
||||
.SH EXAMPLE
|
||||
The following program demonstrates the usage of the fanotify API.
|
||||
It marks the mount passed as argument and waits for events of type
|
||||
.B FAN_PERM_OPEN
|
||||
and
|
||||
.BR FAN_CLOSE_WRITE .
|
||||
When a permission event occurs, a
|
||||
.B FAN_ALLOW
|
||||
response is given.
|
||||
.PP
|
||||
The following output was recorded while editing 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.
|
||||
.SS Example output
|
||||
.in +4n
|
||||
.nf
|
||||
# ./fanotify_example /home
|
||||
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.
|
||||
.fi
|
||||
.in
|
||||
.SS Program source
|
||||
.nf
|
||||
#define _GNU_SOURCE // needed for O_LARGEFILE
|
||||
#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 'fd' */
|
||||
|
||||
void
|
||||
handle_events(int fd)
|
||||
{
|
||||
const struct fanotify_event_metadata *metadata;
|
||||
char buf[4096];
|
||||
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, (void *) &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 = (struct fanotify_event_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.\\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Check that the event contains a file descriptor. */
|
||||
|
||||
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(
|
||||
struct fanotify_response));
|
||||
}
|
||||
|
||||
/* Handle closing of writable file event. */
|
||||
|
||||
if (metadata\->mask & FAN_CLOSE_WRITE) {
|
||||
printf("FAN_CLOSE_WRITE: ");
|
||||
}
|
||||
|
||||
/* Determine path of the file accessed. */
|
||||
|
||||
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] = '\\0';
|
||||
printf("File %s", path);
|
||||
|
||||
/* Close the file descriptor of the event. */
|
||||
|
||||
close(metadata\->fd);
|
||||
printf("\\n");
|
||||
}
|
||||
|
||||
/* Forward pointer 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) {
|
||||
printf("Usage: %s MOUNT\\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Press enter key to terminate.\\n");
|
||||
|
||||
/* 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, \-1,
|
||||
argv[1]) == \-1) {
|
||||
perror("fanotify_mark");
|
||||
close(fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Prepare for polling. */
|
||||
|
||||
nfds = 2;
|
||||
|
||||
/* Console input. */
|
||||
|
||||
fds[0].fd = STDIN_FILENO;
|
||||
fds[0].events = POLLIN;
|
||||
|
||||
/* Fanotify input. */
|
||||
|
||||
fds[1].fd = fd;
|
||||
fds[1].events = POLLIN;
|
||||
|
||||
/* This is the loop to wait for incoming events. */
|
||||
|
||||
printf("Listening for events.\\n");
|
||||
while (1) {
|
||||
poll_num = poll(fds, nfds, \-1);
|
||||
if (poll_num == \-1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
perror("poll");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (poll_num > 0) {
|
||||
if (fds[0].revents & POLLIN) {
|
||||
|
||||
/* Console input is available. Empty stdin and quit. */
|
||||
|
||||
while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\\n')
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (fds[1].revents & POLLIN) {
|
||||
|
||||
/* Fanotify events are available. */
|
||||
|
||||
handle_events(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Close fanotify file descriptor. */
|
||||
|
||||
close(fd);
|
||||
printf("Listening for events stopped.\\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
.fi
|
||||
.SH "SEE ALSO"
|
||||
.ad l
|
||||
.BR fanotify_init (2),
|
||||
.BR fanotify_mark (2),
|
||||
.BR inotify (7)
|
Loading…
Reference in New Issue