fanotify.7, fanotify_init.2: Document FAN_REPORT_NAME

Document fanotify_init(2) flag FAN_REPORT_NAME and the format of
the event info type FAN_EVENT_INFO_TYPE_DFID_NAME.

The fanotify_fid.c example is extended to also report the name of
the created file or subdirectory.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Matthew Bobrowski <mbobrowski@mbobrowski.org>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
Amir Goldstein 2020-08-25 14:40:56 +03:00 committed by Michael Kerrisk
parent e9f14fa0bb
commit ea4f577808
2 changed files with 118 additions and 17 deletions

View File

@ -223,6 +223,60 @@ flag, no event will be reported.
See See
.BR fanotify (7) .BR fanotify (7)
for additional details. for additional details.
.TP
.BR FAN_REPORT_NAME " (since Linux 5.9)"
Events for fanotify groups initialized with this flag will contain additional
information about the name of the directory entry correlated to an event.
This flag must be provided in conjunction with the flag
.BR FAN_REPORT_DIR_FID .
Providing this flag value without
.BR FAN_REPORT_DIR_FID
will result in the error
.BR EINVAL .
This flag may be combined with the flag
.BR FAN_REPORT_FID .
An additional record of type
.BR FAN_EVENT_INFO_TYPE_DFID_NAME ,
which encapsulates the information about the directory entry is included
alongside the generic event metadata structure and substitutes the additional
information record of type
.BR FAN_EVENT_INFO_TYPE_DFID .
The additional record includes a file handle that identifies a directory
filesystem object followed by a name that identifies an entry in that
directory.
For the directory entry modification events
.BR FAN_CREATE ,
.BR FAN_DELETE ,
and
.BR FAN_MOVE ,
the reported name is that of the created/deleted/moved directory entry.
For other events that occur on a directory object, the reported file handle
is that of the directory object itself and the reported name is '.'.
For other events that occur on a non-directory object, the reported file handle
is that of the parent directory object and the reported name is the name of a
directory entry where the object was located at the time of the event.
The rationale behind this logic is that the reported directory file handle can
be passed to
.BR open_by_handle_at (2)
to get an open directory file descriptor and that file descriptor along with
the reported name can be used to call
.BR fstatat (2).
The same rule that applies to record type
.BR FAN_EVENT_INFO_TYPE_DFID
also applies to record type
.BR FAN_EVENT_INFO_TYPE_DFID_NAME \ -
if a non-directory object has no parent, either the event will not be reported
or it will be reported without the directory entry information.
Note that there is no guarantee that the filesystem object will be found at the
location described by the directory entry information at the time the event is
received.
See
.BR fanotify (7)
for additional details.
.TP
.B FAN_REPORT_DFID_NAME
This is a synonym for
.RB ( FAN_REPORT_DIR_FID | FAN_REPORT_NAME ).
.PP .PP
The The
.I event_f_flags .I event_f_flags

View File

@ -467,6 +467,12 @@ the
.IR file_handle .IR file_handle
identifies the modified directory and not the created/deleted/moved child identifies the modified directory and not the created/deleted/moved child
object. object.
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 For other events such as
.BR FAN_OPEN , .BR FAN_OPEN ,
.BR FAN_ATTRIB , .BR FAN_ATTRIB ,
@ -487,7 +493,18 @@ field is
the the
.IR file_handle .IR file_handle
identifies the directory object correlated to the event or the parent directory identifies the directory object correlated to the event or the parent directory
of the non-directory object correlated to the event. 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
.IR file_handle
identifies the same directory object that would be reported with
.BR 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.
.PP .PP
The following macros are provided to iterate over a buffer containing The following macros are provided to iterate over a buffer containing
fanotify event metadata returned by a fanotify event metadata returned by a
@ -672,12 +689,17 @@ events for the monitored directory itself.
Fanotify monitoring of directories is not recursive: Fanotify monitoring of directories is not recursive:
to monitor subdirectories under a directory, to monitor subdirectories under a directory,
additional marks must be created. additional marks must be created.
(But note that the fanotify API provides no way of detecting when a The
subdirectory has been created under a marked directory, .B FAN_CREATE
which makes recursive monitoring difficult.) event can be used for detecting when a subdirectory has been created under
Monitoring mounts offers the capability to monitor a whole directory tree. 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 Monitoring filesystems offers the capability to monitor changes made from
any mount of a filesystem instance. any mount of a filesystem instance in a race free manner.
.PP .PP
The event queue can overflow. The event queue can overflow.
In this case, events are lost. In this case, events are lost.
@ -961,9 +983,8 @@ main(int argc, char *argv[])
.EE .EE
.\" .\"
.SS Example program: fanotify_fid.c .SS Example program: fanotify_fid.c
The second program is an example of fanotify being used with The second program is an example of fanotify being used with a group that
.B FAN_REPORT_FID identifies objects by file handles.
enabled.
The program marks the filesystem object that is passed as The program marks the filesystem object that is passed as
a command-line argument a command-line argument
and waits until an event of type and waits until an event of type
@ -984,7 +1005,7 @@ This is followed by the creation of a regular file,
This results in a This results in a
.B FAN_CREATE .B FAN_CREATE
event being generated and reported against the file's parent watched event being generated and reported against the file's parent watched
directory object. directory object and with the created file name.
Program execution ends once all events captured within the buffer have Program execution ends once all events captured within the buffer have
been processed. been processed.
.PP .PP
@ -994,6 +1015,7 @@ been processed.
Listening for events. Listening for events.
FAN_CREATE (file created): FAN_CREATE (file created):
Directory /home/user has been modified. Directory /home/user has been modified.
Entry 'testfile.txt' is not a subdirectory.
All events processed successfully. Program exiting. All events processed successfully. Program exiting.
$ \fBtouch /home/user/testfile.txt\fP # In another terminal $ \fBtouch /home/user/testfile.txt\fP # In another terminal
@ -1008,7 +1030,7 @@ This specific action results in a
.B FAN_CREATE .B FAN_CREATE
event being generated and is reported with the event being generated and is reported with the
.B FAN_ONDIR .B FAN_ONDIR
flag set. flag set and with the created directory name.
.PP .PP
.in +4n .in +4n
.EX .EX
@ -1016,6 +1038,7 @@ flag set.
Listening for events. Listening for events.
FAN_CREATE | FAN_ONDIR (subdirectory created): FAN_CREATE | FAN_ONDIR (subdirectory created):
Directory /home/user has been modified. Directory /home/user has been modified.
Entry 'testdir' is a subdirectory.
All events processed successfully. Program exiting. All events processed successfully. Program exiting.
$ \fBmkdir \-p /home/user/testdir\fP # In another terminal $ \fBmkdir \-p /home/user/testdir\fP # In another terminal
@ -1048,6 +1071,8 @@ main(int argc, char **argv)
struct file_handle *file_handle; struct file_handle *file_handle;
struct fanotify_event_metadata *metadata; struct fanotify_event_metadata *metadata;
struct fanotify_event_info_fid *fid; struct fanotify_event_info_fid *fid;
const char *file_name;
struct stat sb;
if (argc != 2) { if (argc != 2) {
fprintf(stderr, "Invalid number of command line arguments.\en"); fprintf(stderr, "Invalid number of command line arguments.\en");
@ -1061,10 +1086,10 @@ main(int argc, char **argv)
} }
/* Create an fanotify file descriptor with FAN_REPORT_FID as a flag /* Create an fanotify file descriptor with FAN_REPORT_DFID_NAME as a flag
so that program can receive fid events. */ so that program can receive fid events with directory entry name. */
fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_FID, 0); fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME, 0);
if (fd == \-1) { if (fd == \-1) {
perror("fanotify_init"); perror("fanotify_init");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -1100,7 +1125,13 @@ main(int argc, char **argv)
/* Ensure that the event info is of the correct type */ /* Ensure that the event info is of the correct type */
if (fid\->hdr.info_type != FAN_EVENT_INFO_TYPE_FID) { 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"); fprintf(stderr, "Received unexpected event info type.\en");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -1111,8 +1142,8 @@ main(int argc, char **argv)
if (metadata\->mask == (FAN_CREATE | FAN_ONDIR)) if (metadata\->mask == (FAN_CREATE | FAN_ONDIR))
printf("FAN_CREATE | FAN_ONDIR (subdirectory created):\en"); printf("FAN_CREATE | FAN_ONDIR (subdirectory created):\en");
/* metadata\->fd is set to FAN_NOFD when FAN_REPORT_FID is /* metadata\->fd is set to FAN_NOFD when the group identifies objects
enabled. To obtain a file descriptor for the file object by file handles. To obtain a file descriptor for the file object
corresponding to an event you can use the struct file_handle corresponding to an event you can use the struct file_handle
that\(aqs provided within the fanotify_event_info_fid in that\(aqs provided within the fanotify_event_info_fid in
conjunction with the open_by_handle_at(2) system call. conjunction with the open_by_handle_at(2) system call.
@ -1146,6 +1177,22 @@ main(int argc, char **argv)
path[path_len] = \(aq\e0\(aq; path[path_len] = \(aq\e0\(aq;
printf("\etDirectory \(aq%s\(aq has been modified.\en", path); 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 associated file descriptor for this event */
close(event_fd); close(event_fd);