1FANOTIFY(7) Linux Programmer's Manual FANOTIFY(7)
2
3
4
6 fanotify - monitoring filesystem events
7
9 The fanotify API provides notification and interception of filesystem
10 events. Use cases include virus scanning and hierarchical storage man‐
11 agement. Currently, only a limited set of events is supported. In
12 particular, there is no support for create, delete, and move events.
13 (See inotify(7) for details of an API that does notify those events.)
14
15 Additional capabilities compared to the inotify(7) API include the
16 ability to monitor all of the objects in a mounted filesystem, the
17 ability to make access permission decisions, and the possibility to
18 read or modify files before access by other applications.
19
20 The following system calls are used with this API: fanotify_init(2),
21 fanotify_mark(2), read(2), write(2), and close(2).
22
23 fanotify_init(), fanotify_mark(), and notification groups
24 The fanotify_init(2) system call creates and initializes an fanotify
25 notification group and returns a file descriptor referring to it.
26
27 An fanotify notification group is a kernel-internal object that holds a
28 list of files, directories, filesystems, and mount points for which
29 events shall be created.
30
31 For each entry in an fanotify notification group, two bit masks exist:
32 the mark mask and the ignore mask. The mark mask defines file activi‐
33 ties for which an event shall be created. The ignore mask defines
34 activities for which no event shall be generated. Having these two
35 types of masks permits a filesystem, mount point, or directory to be
36 marked for receiving events, while at the same time ignoring events for
37 specific objects under a mount point or directory.
38
39 The fanotify_mark(2) system call adds a file, directory, filesystem or
40 mount point to a notification group and specifies which events shall be
41 reported (or ignored), or removes or modifies such an entry.
42
43 A possible usage of the ignore mask is for a file cache. Events of
44 interest for a file cache are modification of a file and closing of the
45 same. Hence, the cached directory or mount point is to be marked to
46 receive these events. After receiving the first event informing that a
47 file has been modified, the corresponding cache entry will be invali‐
48 dated. No further modification events for this file are of interest
49 until the file is closed. Hence, the modify event can be added to the
50 ignore mask. Upon receiving the close event, the modify event can be
51 removed from the ignore mask and the file cache entry can be updated.
52
53 The entries in the fanotify notification groups refer to files and
54 directories via their inode number and to mounts via their mount ID.
55 If files or directories are renamed or moved within the same mount, the
56 respective entries survive. If files or directories are deleted or
57 moved to another mount or if filesystems or mounts are unmounted, the
58 corresponding entries are deleted.
59
60 The event queue
61 As events occur on the filesystem objects monitored by a notification
62 group, the fanotify system generates events that are collected in a
63 queue. These events can then be read (using read(2) or similar) from
64 the fanotify file descriptor returned by fanotify_init(2).
65
66 Two types of events are generated: notification events and permission
67 events. Notification events are merely informative and require no
68 action to be taken by the receiving application with the exception
69 being that the file descriptor provided within a generic event must be
70 closed. The closing of file descriptors for each event applies only to
71 applications that have initialized fanotify without using
72 FAN_REPORT_FID (see below). Permission events are requests to the
73 receiving application to decide whether permission for a file access
74 shall be granted. For these events, the recipient must write a
75 response which decides whether access is granted or not.
76
77 An event is removed from the event queue of the fanotify group when it
78 has been read. Permission events that have been read are kept in an
79 internal list of the fanotify group until either a permission decision
80 has been taken by writing to the fanotify file descriptor or the fan‐
81 otify file descriptor is closed.
82
83 Reading fanotify events
84 Calling read(2) for the file descriptor returned by fanotify_init(2)
85 blocks (if the flag FAN_NONBLOCK is not specified in the call to fan‐
86 otify_init(2)) until either a file event occurs or the call is inter‐
87 rupted by a signal (see signal(7)).
88
89 The use of the FAN_REPORT_FID flag in fanotify_init(2) influences what
90 data structures are returned to the event listener for each event.
91 After a successful read(2), the read buffer contains one or more of the
92 following structures:
93
94 struct fanotify_event_metadata {
95 __u32 event_len;
96 __u8 vers;
97 __u8 reserved;
98 __u16 metadata_len;
99 __aligned_u64 mask;
100 __s32 fd;
101 __s32 pid;
102 };
103
104 In the case where FAN_REPORT_FID is supplied as one of the flags to
105 fanotify_init(2), you should also expect to receive the structure
106 detailed below following the generic fanotify_event_metadata structure
107 within the read buffer:
108
109 struct fanotify_event_info_fid {
110 struct fanotify_event_info_header hdr;
111 __kernel_fsid_t fsid;
112 unsigned char file_handle[0];
113 };
114
115 For performance reasons, it is recommended to use a large buffer size
116 (for example, 4096 bytes), so that multiple events can be retrieved by
117 a single read(2).
118
119 The return value of read(2) is the number of bytes placed in the buf‐
120 fer, or -1 in case of an error (but see BUGS).
121
122 The fields of the fanotify_event_metadata structure are as follows:
123
124 event_len
125 This is the length of the data for the current event and the
126 offset to the next event in the buffer. Without FAN_REPORT_FID,
127 the value of event_len is always FAN_EVENT_METADATA_LEN. With
128 FAN_REPORT_FID, event_len also includes the variable length file
129 identifier.
130
131 vers This field holds a version number for the structure. It must be
132 compared to FANOTIFY_METADATA_VERSION to verify that the struc‐
133 tures returned at run time match the structures defined at com‐
134 pile time. In case of a mismatch, the application should aban‐
135 don trying to use the fanotify file descriptor.
136
137 reserved
138 This field is not used.
139
140 metadata_len
141 This is the length of the structure. The field was introduced
142 to facilitate the implementation of optional headers per event
143 type. No such optional headers exist in the current implementa‐
144 tion.
145
146 mask This is a bit mask describing the event (see below).
147
148 fd This is an open file descriptor for the object being accessed,
149 or FAN_NOFD if a queue overflow occurred. If the fanotify file
150 descriptor has been initialized using FAN_REPORT_FID, applica‐
151 tions should expect this value to be set to FAN_NOFD for each
152 event that is received. The file descriptor can be used to
153 access the contents of the monitored file or directory. The
154 reading application is responsible for closing this file
155 descriptor.
156
157 When calling fanotify_init(2), the caller may specify (via the
158 event_f_flags argument) various file status flags that are to be
159 set on the open file description that corresponds to this file
160 descriptor. In addition, the (kernel-internal) FMODE_NONOTIFY
161 file status flag is set on the open file description. This flag
162 suppresses fanotify event generation. Hence, when the receiver
163 of the fanotify event accesses the notified file or directory
164 using this file descriptor, no additional events will be cre‐
165 ated.
166
167 pid If flag FAN_REPORT_TID was set in fanotify_init(2), this is the
168 TID of the thread that caused the event. Otherwise, this the
169 PID of the process that caused the event.
170
171 A program listening to fanotify events can compare this PID to the PID
172 returned by getpid(2), to determine whether the event is caused by the
173 listener itself, or is due to a file access by another process.
174
175 The bit mask in mask indicates which events have occurred for a single
176 filesystem object. Multiple bits may be set in this mask, if more than
177 one event occurred for the monitored filesystem object. In particular,
178 consecutive events for the same filesystem object and originating from
179 the same process may be merged into a single event, with the exception
180 that two permission events are never merged into one queue entry.
181
182 The bits that may appear in mask are as follows:
183
184 FAN_ACCESS
185 A file or a directory (but see BUGS) was accessed (read).
186
187 FAN_OPEN
188 A file or a directory was opened.
189
190 FAN_OPEN_EXEC
191 A file was opened with the intent to be executed. See NOTES in
192 fanotify_mark(2) for additional details.
193
194 FAN_ATTRIB
195 A file or directory metadata was changed.
196
197 FAN_CREATE
198 A child file or directory was created in a watched parent.
199
200 FAN_DELETE
201 A child file or directory was deleted in a watched parent.
202
203 FAN_DELETE_SELF
204 A watched file or directory was deleted.
205
206 FAN_MOVED_FROM
207 A file or directory has been moved from a watched parent direc‐
208 tory.
209
210 FAN_MOVED_TO
211 A file or directory has been moved to a watched parent direc‐
212 tory.
213
214 FAN_MOVE_SELF
215 A watched file or directory was moved.
216
217 FAN_MODIFY
218 A file was modified.
219
220 FAN_CLOSE_WRITE
221 A file that was opened for writing (O_WRONLY or O_RDWR) was
222 closed.
223
224 FAN_CLOSE_NOWRITE
225 A file or directory that was opened read-only (O_RDONLY) was
226 closed.
227
228 FAN_Q_OVERFLOW
229 The event queue exceeded the limit of 16384 entries. This limit
230 can be overridden by specifying the FAN_UNLIMITED_QUEUE flag
231 when calling fanotify_init(2).
232
233 FAN_ACCESS_PERM
234 An application wants to read a file or directory, for example
235 using read(2) or readdir(2). The reader must write a response
236 (as described below) that determines whether the permission to
237 access the filesystem object shall be granted.
238
239 FAN_OPEN_PERM
240 An application wants to open a file or directory. The reader
241 must write a response that determines whether the permission to
242 open the filesystem object shall be granted.
243
244 FAN_OPEN_EXEC_PERM
245 An application wants to open a file for execution. The reader
246 must write a response that determines whether the permission to
247 open the filesystem object for execution shall be granted. See
248 NOTES in fanotify_mark(2) for additional details.
249
250 To check for any close event, the following bit mask may be used:
251
252 FAN_CLOSE
253 A file was closed. This is a synonym for:
254
255 FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE
256
257 To check for any move event, the following bit mask may be used:
258
259 FAN_MOVE
260 A file or directory was moved. This is a synonym for:
261
262 FAN_MOVED_FROM | FAN_MOVED_TO
263
264 The following bits may appear in mask only in conjunction with other
265 event type bits:
266
267 FAN_ONDIR
268 The events described in the mask have occurred on a directory
269 object. Reporting events on directories requires setting this
270 flag in the mark mask. See fanotify_mark(2) for additional
271 details. The FAN_ONDIR flag is reported in an event mask only
272 if the fanotify group has been initialized with the flag
273 FAN_REPORT_FID.
274
275 The fields of the fanotify_event_info_fid structure are as follows:
276
277 hdr This is a structure of type fanotify_event_info_header. It is a
278 generic header that contains information used to describe addi‐
279 tional information attached to the event. For example, when an
280 fanotify file descriptor is created using FAN_REPORT_FID, the
281 info_type field of this header is set to
282 FAN_EVENT_INFO_TYPE_FID. Event listeners can use this field to
283 check that the additional information received for an event is
284 of the correct type. Additionally, the fan‐
285 otify_event_info_header also contains a len field. In the cur‐
286 rent implementation, the value of len is always (event_len -
287 FAN_EVENT_METADATA_LEN).
288
289 fsid This is a unique identifier of the filesystem containing the
290 object associated with the event. It is a structure of type
291 __kernel_fsid_t and contains the same value as f_fsid when call‐
292 ing statfs(2).
293
294 file_handle
295 This is a variable length structure of type file_handle. It is
296 an opaque handle that corresponds to a specified object on a
297 filesystem as returned by name_to_handle_at(2). It can be used
298 to uniquely identify a file on a filesystem and can be passed as
299 an argument to open_by_handle_at(2). Note that for directory
300 entry events, such as FAN_CREATE, FAN_DELETE, and FAN_MOVE, the
301 file_handle describes the modified directory and not the cre‐
302 ated/deleted/moved child object. The events FAN_ATTRIB,
303 FAN_DELETE_SELF, and FAN_MOVE_SELF will carry the file_handle
304 information for the child object if the child object is being
305 watched.
306
307 The following macros are provided to iterate over a buffer containing
308 fanotify event metadata returned by a read(2) from an fanotify file
309 descriptor:
310
311 FAN_EVENT_OK(meta, len)
312 This macro checks the remaining length len of the buffer meta
313 against the length of the metadata structure and the event_len
314 field of the first metadata structure in the buffer.
315
316 FAN_EVENT_NEXT(meta, len)
317 This macro uses the length indicated in the event_len field of
318 the metadata structure pointed to by meta to calculate the
319 address of the next metadata structure that follows meta. len
320 is the number of bytes of metadata that currently remain in the
321 buffer. The macro returns a pointer to the next metadata struc‐
322 ture that follows meta, and reduces len by the number of bytes
323 in the metadata structure that has been skipped over (i.e., it
324 subtracts meta->event_len from len).
325
326 In addition, there is:
327
328 FAN_EVENT_METADATA_LEN
329 This macro returns the size (in bytes) of the structure fan‐
330 otify_event_metadata. This is the minimum size (and currently
331 the only size) of any event metadata.
332
333 Monitoring an fanotify file descriptor for events
334 When an fanotify event occurs, the fanotify file descriptor indicates
335 as readable when passed to epoll(7), poll(2), or select(2).
336
337 Dealing with permission events
338 For permission events, the application must write(2) a structure of the
339 following form to the fanotify file descriptor:
340
341 struct fanotify_response {
342 __s32 fd;
343 __u32 response;
344 };
345
346 The fields of this structure are as follows:
347
348 fd This is the file descriptor from the structure fan‐
349 otify_event_metadata.
350
351 response
352 This field indicates whether or not the permission is to be
353 granted. Its value must be either FAN_ALLOW to allow the file
354 operation or FAN_DENY to deny the file operation.
355
356 If access is denied, the requesting application call will receive an
357 EPERM error.
358
359 Closing the fanotify file descriptor
360 When all file descriptors referring to the fanotify notification group
361 are closed, the fanotify group is released and its resources are freed
362 for reuse by the kernel. Upon close(2), outstanding permission events
363 will be set to allowed.
364
365 /proc/[pid]/fdinfo
366 The file /proc/[pid]/fdinfo/[fd] contains information about fanotify
367 marks for file descriptor fd of process pid. See proc(5) for details.
368
370 In addition to the usual errors for read(2), the following errors can
371 occur when reading from the fanotify file descriptor:
372
373 EINVAL The buffer is too small to hold the event.
374
375 EMFILE The per-process limit on the number of open files has been
376 reached. See the description of RLIMIT_NOFILE in getrlimit(2).
377
378 ENFILE The system-wide limit on the total number of open files has been
379 reached. See /proc/sys/fs/file-max in proc(5).
380
381 ETXTBSY
382 This error is returned by read(2) if O_RDWR or O_WRONLY was
383 specified in the event_f_flags argument when calling fan‐
384 otify_init(2) and an event occurred for a monitored file that is
385 currently being executed.
386
387 In addition to the usual errors for write(2), the following errors can
388 occur when writing to the fanotify file descriptor:
389
390 EINVAL Fanotify access permissions are not enabled in the kernel con‐
391 figuration or the value of response in the response structure is
392 not valid.
393
394 ENOENT The file descriptor fd in the response structure is not valid.
395 This may occur when a response for the permission event has
396 already been written.
397
399 The fanotify API was introduced in version 2.6.36 of the Linux kernel
400 and enabled in version 2.6.37. Fdinfo support was added in version
401 3.8.
402
404 The fanotify API is Linux-specific.
405
407 The fanotify API is available only if the kernel was built with the
408 CONFIG_FANOTIFY configuration option enabled. In addition, fanotify
409 permission handling is available only if the CONFIG_FAN‐
410 OTIFY_ACCESS_PERMISSIONS configuration option is enabled.
411
412 Limitations and caveats
413 Fanotify reports only events that a user-space program triggers through
414 the filesystem API. As a result, it does not catch remote events that
415 occur on network filesystems.
416
417 The fanotify API does not report file accesses and modifications that
418 may occur because of mmap(2), msync(2), and munmap(2).
419
420 Events for directories are created only if the directory itself is
421 opened, read, and closed. Adding, removing, or changing children of a
422 marked directory does not create events for the monitored directory
423 itself.
424
425 Fanotify monitoring of directories is not recursive: to monitor subdi‐
426 rectories under a directory, additional marks must be created. (But
427 note that the fanotify API provides no way of detecting when a subdi‐
428 rectory has been created under a marked directory, which makes recur‐
429 sive monitoring difficult.) Monitoring mounts offers the capability to
430 monitor a whole directory tree. Monitoring filesystems offers the
431 capability to monitor changes made from any mount of a filesystem
432 instance.
433
434 The event queue can overflow. In this case, events are lost.
435
437 Before Linux 3.19, fallocate(2) did not generate fanotify events.
438 Since Linux 3.19, calls to fallocate(2) generate FAN_MODIFY events.
439
440 As of Linux 3.17, the following bugs exist:
441
442 * On Linux, a filesystem object may be accessible through multiple
443 paths, for example, a part of a filesystem may be remounted using
444 the --bind option of mount(8). A listener that marked a mount will
445 be notified only of events that were triggered for a filesystem
446 object using the same mount. Any other event will pass unnoticed.
447
448 * When an event is generated, no check is made to see whether the user
449 ID of the receiving process has authorization to read or write the
450 file before passing a file descriptor for that file. This poses a
451 security risk, when the CAP_SYS_ADMIN capability is set for programs
452 executed by unprivileged users.
453
454 * If a call to read(2) processes multiple events from the fanotify
455 queue and an error occurs, the return value will be the total length
456 of the events successfully copied to the user-space buffer before
457 the error occurred. The return value will not be -1, and errno will
458 not be set. Thus, the reading application has no way to detect the
459 error.
460
462 The two example programs below demonstrate the usage of the fanotify
463 API.
464
465 Example program: fanotify_example.c
466 The first program is an example of fanotify being used with its event
467 object information passed in the form of a file descriptor. The pro‐
468 gram marks the mount point passed as a command-line argument and waits
469 for events of type FAN_OPEN_PERM and FAN_CLOSE_WRITE. When a permis‐
470 sion event occurs, a FAN_ALLOW response is given.
471
472 The following shell session shows an example of running this program.
473 This session involved editing the file /home/user/temp/notes. Before
474 the file was opened, a FAN_OPEN_PERM event occurred. After the file
475 was closed, a FAN_CLOSE_WRITE event occurred. Execution of the program
476 ends when the user presses the ENTER key.
477
478 # ./fanotify_example /home
479 Press enter key to terminate.
480 Listening for events.
481 FAN_OPEN_PERM: File /home/user/temp/notes
482 FAN_CLOSE_WRITE: File /home/user/temp/notes
483
484 Listening for events stopped.
485
486 Program source: fanotify_example.c
487
488 #define _GNU_SOURCE /* Needed to get O_LARGEFILE definition */
489 #include <errno.h>
490 #include <fcntl.h>
491 #include <limits.h>
492 #include <poll.h>
493 #include <stdio.h>
494 #include <stdlib.h>
495 #include <sys/fanotify.h>
496 #include <unistd.h>
497
498 /* Read all available fanotify events from the file descriptor 'fd' */
499
500 static void
501 handle_events(int fd)
502 {
503 const struct fanotify_event_metadata *metadata;
504 struct fanotify_event_metadata buf[200];
505 ssize_t len;
506 char path[PATH_MAX];
507 ssize_t path_len;
508 char procfd_path[PATH_MAX];
509 struct fanotify_response response;
510
511 /* Loop while events can be read from fanotify file descriptor */
512
513 for (;;) {
514
515 /* Read some events */
516
517 len = read(fd, (void *) &buf, sizeof(buf));
518 if (len == -1 && errno != EAGAIN) {
519 perror("read");
520 exit(EXIT_FAILURE);
521 }
522
523 /* Check if end of available data reached */
524
525 if (len <= 0)
526 break;
527
528 /* Point to the first event in the buffer */
529
530 metadata = buf;
531
532 /* Loop over all events in the buffer */
533
534 while (FAN_EVENT_OK(metadata, len)) {
535
536 /* Check that run-time and compile-time structures match */
537
538 if (metadata->vers != FANOTIFY_METADATA_VERSION) {
539 fprintf(stderr,
540 "Mismatch of fanotify metadata version.\n");
541 exit(EXIT_FAILURE);
542 }
543
544 /* metadata->fd contains either FAN_NOFD, indicating a
545 queue overflow, or a file descriptor (a nonnegative
546 integer). Here, we simply ignore queue overflow. */
547
548 if (metadata->fd >= 0) {
549
550 /* Handle open permission event */
551
552 if (metadata->mask & FAN_OPEN_PERM) {
553 printf("FAN_OPEN_PERM: ");
554
555 /* Allow file to be opened */
556
557 response.fd = metadata->fd;
558 response.response = FAN_ALLOW;
559 write(fd, &response,
560 sizeof(struct fanotify_response));
561 }
562
563 /* Handle closing of writable file event */
564
565 if (metadata->mask & FAN_CLOSE_WRITE)
566 printf("FAN_CLOSE_WRITE: ");
567
568 /* Retrieve and print pathname of the accessed file */
569
570 snprintf(procfd_path, sizeof(procfd_path),
571 "/proc/self/fd/%d", metadata->fd);
572 path_len = readlink(procfd_path, path,
573 sizeof(path) - 1);
574 if (path_len == -1) {
575 perror("readlink");
576 exit(EXIT_FAILURE);
577 }
578
579 path[path_len] = '\0';
580 printf("File %s\n", path);
581
582 /* Close the file descriptor of the event */
583
584 close(metadata->fd);
585 }
586
587 /* Advance to next event */
588
589 metadata = FAN_EVENT_NEXT(metadata, len);
590 }
591 }
592 }
593
594 int
595 main(int argc, char *argv[])
596 {
597 char buf;
598 int fd, poll_num;
599 nfds_t nfds;
600 struct pollfd fds[2];
601
602 /* Check mount point is supplied */
603
604 if (argc != 2) {
605 fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
606 exit(EXIT_FAILURE);
607 }
608
609 printf("Press enter key to terminate.\n");
610
611 /* Create the file descriptor for accessing the fanotify API */
612
613 fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
614 O_RDONLY | O_LARGEFILE);
615 if (fd == -1) {
616 perror("fanotify_init");
617 exit(EXIT_FAILURE);
618 }
619
620 /* Mark the mount for:
621 - permission events before opening files
622 - notification events after closing a write-enabled
623 file descriptor */
624
625 if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
626 FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD,
627 argv[1]) == -1) {
628 perror("fanotify_mark");
629 exit(EXIT_FAILURE);
630 }
631
632 /* Prepare for polling */
633
634 nfds = 2;
635
636 /* Console input */
637
638 fds[0].fd = STDIN_FILENO;
639 fds[0].events = POLLIN;
640
641 /* Fanotify input */
642
643 fds[1].fd = fd;
644 fds[1].events = POLLIN;
645
646 /* This is the loop to wait for incoming events */
647
648 printf("Listening for events.\n");
649
650 while (1) {
651 poll_num = poll(fds, nfds, -1);
652 if (poll_num == -1) {
653 if (errno == EINTR) /* Interrupted by a signal */
654 continue; /* Restart poll() */
655
656 perror("poll"); /* Unexpected error */
657 exit(EXIT_FAILURE);
658 }
659
660 if (poll_num > 0) {
661 if (fds[0].revents & POLLIN) {
662
663 /* Console input is available: empty stdin and quit */
664
665 while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n')
666 continue;
667 break;
668 }
669
670 if (fds[1].revents & POLLIN) {
671
672 /* Fanotify events are available */
673
674 handle_events(fd);
675 }
676 }
677 }
678
679 printf("Listening for events stopped.\n");
680 exit(EXIT_SUCCESS);
681 }
682
683 Example program: fanotify_fid.c
684 The second program is an example of fanotify being used with
685 FAN_REPORT_FID enabled. The program marks the filesystem object that
686 is passed as a command-line argument and waits until an event of type
687 FAN_CREATE has occurred. The event mask indicates which type of
688 filesystem object—either a file or a directory—was created. Once all
689 events have been read from the buffer and processed accordingly, the
690 program simply terminates.
691
692 The following shell sessions show two different invocations of this
693 program, with different actions performed on a watched object.
694
695 The first session shows a mark being placed on /home/user. This is
696 followed by the creation of a regular file, /home/user/testfile.txt.
697 This results in a FAN_CREATE event being generated and reported against
698 the file's parent watched directory object. Program execution ends
699 once all events captured within the buffer have been processed.
700
701 # ./fanotify_fid /home/user
702 Listening for events.
703 FAN_CREATE (file created):
704 Directory /home/user has been modified.
705 All events processed successfully. Program exiting.
706
707 $ touch /home/user/testfile.txt # In another terminal
708
709 The second session shows a mark being placed on /home/user. This is
710 followed by the creation of a directory, /home/user/testdir. This spe‐
711 cific action results in a FAN_CREATE event being generated and is
712 reported with the FAN_ONDIR flag set.
713
714 # ./fanotify_fid /home/user
715 Listening for events.
716 FAN_CREATE | FAN_ONDIR (subdirectory created):
717 Directory /home/user has been modified.
718 All events processed successfully. Program exiting.
719
720 $ mkdir -p /home/user/testdir # In another terminal
721
722 Program source: fanotify_fid.c
723
724 #define _GNU_SOURCE
725 #include <errno.h>
726 #include <fcntl.h>
727 #include <limits.h>
728 #include <stdio.h>
729 #include <stdlib.h>
730 #include <sys/types.h>
731 #include <sys/stat.h>
732 #include <sys/fanotify.h>
733 #include <unistd.h>
734
735 #define BUF_SIZE 256
736
737 int
738 main(int argc, char **argv)
739 {
740 int fd, ret, event_fd, mount_fd;
741 ssize_t len, path_len;
742 char path[PATH_MAX];
743 char procfd_path[PATH_MAX];
744 char events_buf[BUF_SIZE];
745 struct file_handle *file_handle;
746 struct fanotify_event_metadata *metadata;
747 struct fanotify_event_info_fid *fid;
748
749 if (argc != 2) {
750 fprintf(stderr, "Invalid number of command line arguments.\n");
751 exit(EXIT_FAILURE);
752 }
753
754 mount_fd = open(argv[1], O_DIRECTORY | O_RDONLY);
755 if (mount_fd == -1) {
756 perror(argv[1]);
757 exit(EXIT_FAILURE);
758 }
759
760
761 /* Create an fanotify file descriptor with FAN_REPORT_FID as a flag
762 so that program can receive fid events. */
763
764 fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_FID, 0);
765 if (fd == -1) {
766 perror("fanotify_init");
767 exit(EXIT_FAILURE);
768 }
769
770 /* Place a mark on the filesystem object supplied in argv[1]. */
771
772 ret = fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_ONLYDIR,
773 FAN_CREATE | FAN_ONDIR,
774 AT_FDCWD, argv[1]);
775 if (ret == -1) {
776 perror("fanotify_mark");
777 exit(EXIT_FAILURE);
778 }
779
780 printf("Listening for events.\n");
781
782 /* Read events from the event queue into a buffer */
783
784 len = read(fd, (void *) &events_buf, sizeof(events_buf));
785 if (len == -1 && errno != EAGAIN) {
786 perror("read");
787 exit(EXIT_FAILURE);
788 }
789
790 /* Process all events within the buffer */
791
792 for (metadata = (struct fanotify_event_metadata *) events_buf;
793 FAN_EVENT_OK(metadata, len);
794 metadata = FAN_EVENT_NEXT(metadata, len)) {
795 fid = (struct fanotify_event_info_fid *) (metadata + 1);
796 file_handle = (struct file_handle *) fid->handle;
797
798 /* Ensure that the event info is of the correct type */
799
800 if (fid->hdr.info_type != FAN_EVENT_INFO_TYPE_FID) {
801 fprintf(stderr, "Received unexpected event info type.\n");
802 exit(EXIT_FAILURE);
803 }
804
805 if (metadata->mask == FAN_CREATE)
806 printf("FAN_CREATE (file created):\n");
807
808 if (metadata->mask == (FAN_CREATE | FAN_ONDIR))
809 printf("FAN_CREATE | FAN_ONDIR (subdirectory created):\n");
810
811 /* metadata->fd is set to FAN_NOFD when FAN_REPORT_FID is
812 enabled. To obtain a file descriptor for the file object
813 corresponding to an event you can use the struct file_handle
814 that's provided within the fanotify_event_info_fid in
815 conjunction with the open_by_handle_at(2) system call.
816 A check for ESTALE is done to accommodate for the situation
817 where the file handle for the object was deleted prior to
818 this system call. */
819
820 event_fd = open_by_handle_at(mount_fd, file_handle, O_RDONLY);
821 if (event_fd == -1) {
822 if (errno == ESTALE) {
823 printf("File handle is no longer valid. "
824 "File has been deleted\n");
825 continue;
826 } else {
827 perror("open_by_handle_at");
828 exit(EXIT_FAILURE);
829 }
830 }
831
832 snprintf(procfd_path, sizeof(procfd_path), "/proc/self/fd/%d",
833 event_fd);
834
835 /* Retrieve and print the path of the modified dentry */
836
837 path_len = readlink(procfd_path, path, sizeof(path) - 1);
838 if (path_len == -1) {
839 perror("readlink");
840 exit(EXIT_FAILURE);
841 }
842
843 path[path_len] = '\0';
844 printf("\tDirectory '%s' has been modified.\n", path);
845
846 /* Close associated file descriptor for this event */
847
848 close(event_fd);
849 }
850
851 printf("All events processed successfully. Program exiting.\n");
852 exit(EXIT_SUCCESS);
853 }
854
856 fanotify_init(2), fanotify_mark(2), inotify(7)
857
859 This page is part of release 5.07 of the Linux man-pages project. A
860 description of the project, information about reporting bugs, and the
861 latest version of this page, can be found at
862 https://www.kernel.org/doc/man-pages/.
863
864
865
866Linux 2020-06-09 FANOTIFY(7)