+ 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
+.B FAN_REPORT_FID
+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
+has occurred.
+The event mask indicates which type of filesystem object\(emeither
+a file or a directory\(emwas created".
+Once all events have been read from the buffer and processed accordingly,
+the program simply terminates.
+.PP
+The following shell sessions show two different invocations of
+this program, with different actions performed on a watched object.
+.PP
+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 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.
+.PP
+.in +4n
+.EX
+# \fB./fanotify_fid /home/user\fP
+Listening for events.
+FAN_CREATE (file created): Directory /home/user has been modified.
+All events processed successfully. Program exiting.
+
+$ \fBtouch /home/user/testing\fP # In another terminal
+.EE
+.in
+.PP
+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 the program producing a
+.B FAN_CREATE
+and
+.B FAN_ONDIR
+event.
+.PP
+.in +4n
+.EX
+# \fB./fanotify_fid /home/user\fP
+Listening for events.
+FAN_CREATE | FAN_ONDIR (subdirectory created):
+ Directory /home/user has been modified.
+All events processed successfully. Program exiting.
+
+$ \fBmkdir \-p /home/user/testing\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;
+ 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;
+
+ if (argc != 2) {
+ fprintf(stderr, "Invalid number of command line arguments.\e\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Create an fanotify file descriptor with FAN_REPORT_FID as a flag
+ so that program can receive fid events. */
+
+ fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_FID, 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.\e\n");
+
+ /* Read events from the event queue into a buffer */
+
+ len = read(fd, (void *) &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) {
+ fprintf(stderr, "Received unexpected event info type.\e\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (metadata->mask == FAN_CREATE)
+ printf("FAN_CREATE (file created):");
+
+ if (metadata->mask == FAN_CREATE | FAN_ONDIR)
+ printf("FAN_CREATE | FAN_ONDIR (subdirectory created):");
+
+ /* metadata->fd is set to FAN_NOFD when FAN_REPORT_FID is enabled.
+ To obtain a file descriptor for the file object corresponding to
+ an event you can use the struct file_handle that\(aqs 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(AT_FDCWD, file_handle, O_RDONLY);
+ if (ret == \-1) {
+ if (errno == ESTALE) {
+ printf("File handle is no longer valid. "
+ "File has been deleted\e\n");
+ 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\e\0\(aq;
+ printf("\etDirectory \(aq%s\(aq has been modified.\e\n", path);
+
+ /* Close associated file descriptor for this event */
+
+ close(event_fd);
+ }
+
+ printf("All events processed successfully. Program exiting.\e\n");