]>
Commit | Line | Data |
---|---|---|
597aaea2 | 1 | .\" Copyright (C) 2013, Heinrich Schuchardt <xypron.glpk@gmx.de> |
89613d50 | 2 | .\" and Copyright (C) 2014, Michael Kerrisk <mtk.manpages@gmail.com> |
597aaea2 HS |
3 | .\" |
4 | .\" %%%LICENSE_START(VERBATIM) | |
5 | .\" Permission is granted to make and distribute verbatim copies of this | |
6 | .\" manual provided the copyright notice and this permission notice are | |
7 | .\" preserved on all copies. | |
8 | .\" | |
9 | .\" Permission is granted to copy and distribute modified versions of | |
10 | .\" this manual under the conditions for verbatim copying, provided that | |
11 | .\" the entire resulting derived work is distributed under the terms of | |
12 | .\" a permission notice identical to this one. | |
13 | .\" | |
14 | .\" Since the Linux kernel and libraries are constantly changing, this | |
15 | .\" manual page may be incorrect or out-of-date. The author(s) assume. | |
16 | .\" no responsibility for errors or omissions, or for damages resulting. | |
17 | .\" from the use of the information contained herein. The author(s) may. | |
18 | .\" not have taken the same level of care in the production of this. | |
19 | .\" manual, which is licensed free of charge, as they might when working. | |
20 | .\" professionally. | |
21 | .\" | |
22 | .\" Formatted or processed versions of this manual, if unaccompanied by | |
23 | .\" the source, must acknowledge the copyright and authors of this work. | |
24 | .\" %%%LICENSE_END | |
63121bd4 | 25 | .TH FANOTIFY 7 2019-08-02 "Linux" "Linux Programmer's Manual" |
597aaea2 HS |
26 | .SH NAME |
27 | fanotify \- monitoring filesystem events | |
28 | .SH DESCRIPTION | |
1b24e2ee MK |
29 | The fanotify API provides notification and interception of |
30 | filesystem events. | |
597aaea2 HS |
31 | Use cases include virus scanning and hierarchical storage management. |
32 | Currently, only a limited set of events is supported. | |
7ea227bd | 33 | In particular, there is no support for create, delete, and move events. |
d9b086d6 MK |
34 | (See |
35 | .BR inotify (7) | |
36 | for details of an API that does notify those events.) | |
a721e8b2 | 37 | .PP |
597aaea2 HS |
38 | Additional capabilities compared to the |
39 | .BR inotify (7) | |
4a57583f MK |
40 | API include the ability to monitor all of the objects |
41 | in a mounted filesystem, | |
42 | the ability to make access permission decisions, and the | |
597aaea2 | 43 | possibility to read or modify files before access by other applications. |
a721e8b2 | 44 | .PP |
597aaea2 HS |
45 | The following system calls are used with this API: |
46 | .BR fanotify_init (2), | |
47 | .BR fanotify_mark (2), | |
597aaea2 HS |
48 | .BR read (2), |
49 | .BR write (2), | |
50 | and | |
51 | .BR close (2). | |
6c693f6d | 52 | .SS fanotify_init(), fanotify_mark(), and notification groups |
397ff1fd | 53 | The |
597aaea2 | 54 | .BR fanotify_init (2) |
397ff1fd MK |
55 | system call creates and initializes an fanotify notification group |
56 | and returns a file descriptor referring to it. | |
597aaea2 | 57 | .PP |
7ea227bd | 58 | An fanotify notification group is a kernel-internal object that holds |
953d1e07 | 59 | a list of files, directories, filesystems, and mount points for which |
b2f8214d | 60 | events shall be created. |
597aaea2 | 61 | .PP |
7ea227bd MK |
62 | For each entry in an fanotify notification group, two bit masks exist: the |
63 | .I mark | |
64 | mask and the | |
65 | .I ignore | |
66 | mask. | |
67 | The mark mask defines file activities for which an event shall be created. | |
68 | The ignore mask defines activities for which no event shall be generated. | |
953d1e07 | 69 | Having these two types of masks permits a filesystem, mount point, or |
b2f8214d AG |
70 | directory to be marked for receiving events, while at the same time |
71 | ignoring events for specific objects under a mount point or directory. | |
597aaea2 | 72 | .PP |
ffb30e75 | 73 | The |
6c693f6d | 74 | .BR fanotify_mark (2) |
b2f8214d AG |
75 | system call adds a file, directory, filesystem or mount point to a |
76 | notification group and specifies which events | |
6c693f6d MK |
77 | shall be reported (or ignored), or removes or modifies such an entry. |
78 | .PP | |
597aaea2 HS |
79 | A possible usage of the ignore mask is for a file cache. |
80 | Events of interest for a file cache are modification of a file and closing | |
81 | of the same. | |
82 | Hence, the cached directory or mount point is to be marked to receive these | |
83 | events. | |
1b24e2ee MK |
84 | After receiving the first event informing that a file has been modified, |
85 | the corresponding cache entry will be invalidated. | |
86 | No further modification events for this file are of interest until the file | |
87 | is closed. | |
597aaea2 | 88 | Hence, the modify event can be added to the ignore mask. |
5e443a5f | 89 | Upon receiving the close event, the modify event can be removed from the |
597aaea2 HS |
90 | ignore mask and the file cache entry can be updated. |
91 | .PP | |
1b24e2ee MK |
92 | The entries in the fanotify notification groups refer to files and |
93 | directories via their inode number and to mounts via their mount ID. | |
7d3c593b | 94 | If files or directories are renamed or moved within the same mount, |
1b24e2ee | 95 | the respective entries survive. |
b2f8214d AG |
96 | If files or directories are deleted or moved to another mount or if |
97 | filesystems or mounts are unmounted, the corresponding entries are deleted. | |
ad02dd1f | 98 | .SS The event queue |
77bba7b5 | 99 | As events occur on the filesystem objects monitored by a notification group, |
c9120323 MK |
100 | the fanotify system generates events that are collected in a queue. |
101 | These events can then be read (using | |
102 | .BR read (2) | |
103 | or similar) | |
104 | from the fanotify file descriptor | |
105 | returned by | |
106 | .BR fanotify_init (2). | |
a721e8b2 | 107 | .PP |
c9120323 | 108 | Two types of events are generated: |
4a57583f MK |
109 | .I notification |
110 | events and | |
111 | .I permission | |
112 | events. | |
c9120323 MK |
113 | Notification events are merely informative |
114 | and require no action to be taken by | |
0a4db6dc MB |
115 | the receiving application with the exception being that the file |
116 | descriptor provided within a generic event must be closed. | |
817c8240 | 117 | The closing of file descriptors for each event applies only to |
0a4db6dc MB |
118 | applications that have initialized fanotify without using |
119 | .BR FAN_REPORT_FID | |
120 | (see below). | |
1b24e2ee MK |
121 | Permission events are requests to the receiving application to decide |
122 | whether permission for a file access shall be granted. | |
597aaea2 HS |
123 | For these events, the recipient must write a response which decides whether |
124 | access is granted or not. | |
a721e8b2 | 125 | .PP |
33022419 MK |
126 | An event is removed from the event queue of the fanotify group |
127 | when it has been read. | |
a6625006 | 128 | Permission events that have been read are kept in an internal list of the |
33022419 MK |
129 | fanotify group until either a permission decision has been taken by |
130 | writing to the fanotify file descriptor or the fanotify file descriptor | |
131 | is closed. | |
ad02dd1f | 132 | .SS Reading fanotify events |
597aaea2 HS |
133 | Calling |
134 | .BR read (2) | |
135 | for the file descriptor returned by | |
136 | .BR fanotify_init (2) | |
137 | blocks (if the flag | |
138 | .B FAN_NONBLOCK | |
139 | is not specified in the call to | |
140 | .BR fanotify_init (2)) | |
141 | until either a file event occurs or the call is interrupted by a signal | |
142 | (see | |
143 | .BR signal (7)). | |
a721e8b2 | 144 | .PP |
f5230cf1 | 145 | The use of the |
0a4db6dc | 146 | .BR FAN_REPORT_FID |
f5230cf1 | 147 | flag in |
0a4db6dc | 148 | .BR fanotify_init (2) |
58ba48e4 | 149 | influences what data structures are returned to the event listener for each |
f5230cf1 | 150 | event. |
597aaea2 | 151 | After a successful |
7ea227bd | 152 | .BR read (2), |
597aaea2 | 153 | the read buffer contains one or more of the following structures: |
a721e8b2 | 154 | .PP |
597aaea2 | 155 | .in +4n |
b8302363 | 156 | .EX |
597aaea2 HS |
157 | struct fanotify_event_metadata { |
158 | __u32 event_len; | |
159 | __u8 vers; | |
160 | __u8 reserved; | |
161 | __u16 metadata_len; | |
162 | __aligned_u64 mask; | |
163 | __s32 fd; | |
164 | __s32 pid; | |
165 | }; | |
b8302363 | 166 | .EE |
597aaea2 | 167 | .in |
f2ac23e7 | 168 | .PP |
817c8240 | 169 | In the case where |
0a4db6dc MB |
170 | .BR FAN_REPORT_FID |
171 | is supplied as one of the flags to | |
172 | .BR fanotify_init (2), | |
173 | you should also expect to receive the structure detailed below following | |
174 | the generic | |
175 | .I fanotify_event_metadata | |
176 | structure within the read buffer: | |
177 | .PP | |
178 | .in +4n | |
179 | .EX | |
180 | struct fanotify_event_info_fid { | |
181 | struct fanotify_event_info_header hdr; | |
182 | __kernel_fsid_t fsid; | |
183 | unsigned char file_handle[0]; | |
184 | }; | |
185 | .EE | |
186 | .in | |
187 | .PP | |
3253bbc3 MK |
188 | For performance reasons, it is recommended to use a large |
189 | buffer size (for example, 4096 bytes), | |
190 | so that multiple events can be retrieved by a single | |
191 | .BR read (2). | |
a721e8b2 | 192 | .PP |
3253bbc3 MK |
193 | The return value of |
194 | .BR read (2) | |
195 | is the number of bytes placed in the buffer, | |
f96adfdc | 196 | or \-1 in case of an error (but see BUGS). |
a721e8b2 | 197 | .PP |
4a57583f MK |
198 | The fields of the |
199 | .I fanotify_event_metadata | |
200 | structure are as follows: | |
9d76d630 | 201 | .TP |
597aaea2 | 202 | .I event_len |
1b24e2ee MK |
203 | This is the length of the data for the current event and the offset |
204 | to the next event in the buffer. | |
0a4db6dc MB |
205 | Without |
206 | .BR FAN_REPORT_FID , | |
207 | the value of | |
597aaea2 HS |
208 | .I event_len |
209 | is always | |
210 | .BR FAN_EVENT_METADATA_LEN . | |
0a4db6dc MB |
211 | With |
212 | .BR FAN_REPORT_FID , | |
213 | .I event_len | |
214 | also includes the variable length file identifier. | |
597aaea2 HS |
215 | .TP |
216 | .I vers | |
6d8c5d01 | 217 | This field holds a version number for the structure. |
597aaea2 HS |
218 | It must be compared to |
219 | .B FANOTIFY_METADATA_VERSION | |
29c0586f | 220 | to verify that the structures returned at run time match |
6d8c5d01 | 221 | the structures defined at compile time. |
597aaea2 HS |
222 | In case of a mismatch, the application should abandon trying to use the |
223 | fanotify file descriptor. | |
224 | .TP | |
225 | .I reserved | |
226 | This field is not used. | |
227 | .TP | |
228 | .I metadata_len | |
229 | This is the length of the structure. | |
1b24e2ee MK |
230 | The field was introduced to facilitate the implementation of |
231 | optional headers per event type. | |
597aaea2 HS |
232 | No such optional headers exist in the current implementation. |
233 | .TP | |
234 | .I mask | |
4a57583f | 235 | This is a bit mask describing the event (see below). |
597aaea2 HS |
236 | .TP |
237 | .I fd | |
238 | This is an open file descriptor for the object being accessed, or | |
239 | .B FAN_NOFD | |
240 | if a queue overflow occurred. | |
0a4db6dc MB |
241 | If the fanotify file descriptor has been initialized using |
242 | .BR FAN_REPORT_FID , | |
243 | applications should expect this value to be set to | |
244 | .B FAN_NOFD | |
245 | for each event that is received. | |
1b24e2ee MK |
246 | The file descriptor can be used to access the contents |
247 | of the monitored file or directory. | |
4a57583f MK |
248 | The reading application is responsible for closing this file descriptor. |
249 | .IP | |
a4cd12a9 | 250 | When calling |
ce87be97 | 251 | .BR fanotify_init (2), |
a4cd12a9 MK |
252 | the caller may specify (via the |
253 | .I event_f_flags | |
254 | argument) various file status flags that are to be set | |
255 | on the open file description that corresponds to this file descriptor. | |
256 | In addition, the (kernel-internal) | |
597aaea2 | 257 | .B FMODE_NONOTIFY |
a4cd12a9 | 258 | file status flag is set on the open file description. |
597aaea2 HS |
259 | This flag suppresses fanotify event generation. |
260 | Hence, when the receiver of the fanotify event accesses the notified file or | |
261 | directory using this file descriptor, no additional events will be created. | |
597aaea2 HS |
262 | .TP |
263 | .I pid | |
ebfb6fee | 264 | If flag |
265 | .B FAN_REPORT_TID | |
266 | was set in | |
267 | .BR fanotify_init (2), | |
268 | this is the TID of the thread that caused the event. | |
269 | Otherwise, this the PID of the process that caused the event. | |
270 | .PP | |
1b24e2ee MK |
271 | A program listening to fanotify events can compare this PID |
272 | to the PID returned by | |
597aaea2 | 273 | .BR getpid (2), |
1b24e2ee | 274 | to determine whether the event is caused by the listener itself, |
4a57583f | 275 | or is due to a file access by another process. |
597aaea2 HS |
276 | .PP |
277 | The bit mask in | |
278 | .I mask | |
4a57583f | 279 | indicates which events have occurred for a single filesystem object. |
29325644 | 280 | Multiple bits may be set in this mask, |
77bba7b5 | 281 | if more than one event occurred for the monitored filesystem object. |
75c3e3bd MK |
282 | In particular, |
283 | consecutive events for the same filesystem object and originating from the | |
284 | same process may be merged into a single event, with the exception that two | |
285 | permission events are never merged into one queue entry. | |
286 | .PP | |
29325644 MK |
287 | The bits that may appear in |
288 | .I mask | |
289 | are as follows: | |
597aaea2 HS |
290 | .TP |
291 | .B FAN_ACCESS | |
292 | A file or a directory (but see BUGS) was accessed (read). | |
293 | .TP | |
294 | .B FAN_OPEN | |
295 | A file or a directory was opened. | |
296 | .TP | |
fc37d2f1 MB |
297 | .B FAN_OPEN_EXEC |
298 | A file was opened with the intent to be executed. | |
fd1eb8a7 | 299 | See NOTES in |
fc37d2f1 MB |
300 | .BR fanotify_mark (2) |
301 | for additional details. | |
302 | .TP | |
0a4db6dc MB |
303 | .B FAN_ATTRIB |
304 | A file or directory metadata was changed. | |
305 | .TP | |
306 | .B FAN_CREATE | |
307 | A child file or directory was created in a watched parent. | |
308 | .TP | |
309 | .B FAN_DELETE | |
310 | A child file or directory was deleted in a watched parent. | |
311 | .TP | |
312 | .B FAN_DELETE_SELF | |
313 | A watched file or directory was deleted. | |
314 | .TP | |
315 | .B FAN_MOVED_FROM | |
316 | A file or directory has been moved from a watched parent directory. | |
317 | .TP | |
318 | .B FAN_MOVED_TO | |
319 | A file or directory has been moved to a watched parent directory. | |
320 | .TP | |
321 | .B FAN_MOVE_SELF | |
322 | A watched file or directory was moved. | |
323 | .TP | |
597aaea2 HS |
324 | .B FAN_MODIFY |
325 | A file was modified. | |
326 | .TP | |
a93e5c95 AG |
327 | .B FAN_DIR_MODIFY |
328 | A directory entry was created, deleted or moved. | |
329 | .TP | |
597aaea2 HS |
330 | .B FAN_CLOSE_WRITE |
331 | A file that was opened for writing | |
332 | .RB ( O_WRONLY | |
333 | or | |
334 | .BR O_RDWR ) | |
335 | was closed. | |
336 | .TP | |
337 | .B FAN_CLOSE_NOWRITE | |
02a18e0f | 338 | A file or directory that was opened read-only |
597aaea2 | 339 | .RB ( O_RDONLY ) |
02a18e0f | 340 | was closed. |
597aaea2 HS |
341 | .TP |
342 | .B FAN_Q_OVERFLOW | |
343 | The event queue exceeded the limit of 16384 entries. | |
4a57583f MK |
344 | This limit can be overridden by specifying the |
345 | .BR FAN_UNLIMITED_QUEUE | |
346 | flag when calling | |
347 | .BR fanotify_init (2). | |
597aaea2 HS |
348 | .TP |
349 | .B FAN_ACCESS_PERM | |
350 | An application wants to read a file or directory, for example using | |
351 | .BR read (2) | |
352 | or | |
353 | .BR readdir (2). | |
4a57583f MK |
354 | The reader must write a response (as described below) |
355 | that determines whether the permission to | |
597aaea2 HS |
356 | access the filesystem object shall be granted. |
357 | .TP | |
358 | .B FAN_OPEN_PERM | |
359 | An application wants to open a file or directory. | |
360 | The reader must write a response that determines whether the permission to | |
361 | open the filesystem object shall be granted. | |
fc37d2f1 MB |
362 | .TP |
363 | .B FAN_OPEN_EXEC_PERM | |
364 | An application wants to open a file for execution. | |
365 | The reader must write a response that determines whether the permission to | |
366 | open the filesystem object for execution shall be granted. | |
fd1eb8a7 | 367 | See NOTES in |
fc37d2f1 MB |
368 | .BR fanotify_mark (2) |
369 | for additional details. | |
597aaea2 HS |
370 | .PP |
371 | To check for any close event, the following bit mask may be used: | |
372 | .TP | |
373 | .B FAN_CLOSE | |
f897ec11 | 374 | A file was closed. |
4a57583f | 375 | This is a synonym for: |
a721e8b2 | 376 | .IP |
f897ec11 | 377 | FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE |
597aaea2 | 378 | .PP |
0a4db6dc MB |
379 | To check for any move event, the following bit mask may be used: |
380 | .TP | |
381 | .B FAN_MOVE | |
382 | A file or directory was moved. | |
383 | This is a synonym for: | |
384 | .IP | |
385 | FAN_MOVED_FROM | FAN_MOVED_TO | |
386 | .PP | |
387 | The fields of the | |
388 | .I fanotify_event_info_fid | |
389 | structure are as follows: | |
390 | .TP | |
391 | .I hdr | |
392 | This is a structure of type | |
393 | .IR fanotify_event_info_header . | |
394 | It is a generic header that contains information used to describe | |
395 | additional information attached to the event. | |
396 | For example, when an fanotify file descriptor is created using | |
817c8240 | 397 | .BR FAN_REPORT_FID , |
0a4db6dc MB |
398 | the |
399 | .I info_type | |
400 | field of this header is set to | |
a93e5c95 AG |
401 | .BR FAN_EVENT_INFO_TYPE_FID |
402 | or | |
403 | .BR FAN_EVENT_INFO_TYPE_DFID_NAME . | |
404 | Event listeners can use this field to check what additional information | |
405 | is received for an event. | |
0a4db6dc MB |
406 | Additionally, the |
407 | .I fanotify_event_info_header | |
408 | also contains a | |
409 | .I len | |
410 | field. | |
411 | In the current implementation, the value of | |
412 | .I len | |
5ff63f51 | 413 | is always (event_len \- FAN_EVENT_METADATA_LEN). |
0a4db6dc MB |
414 | .TP |
415 | .I fsid | |
416 | This is a unique identifier of the filesystem containing the object | |
417 | associated with the event. | |
418 | It is a structure of type | |
419 | .I __kernel_fsid_t | |
420 | and contains the same value as | |
421 | .I f_fsid | |
422 | when calling | |
423 | .BR statfs (2). | |
424 | .TP | |
425 | .I file_handle | |
426 | This is a variable length structure of type | |
427 | .IR file_handle . | |
428 | It is an opaque handle that corresponds to a specified object on a | |
429 | filesystem as returned by | |
817c8240 | 430 | .BR name_to_handle_at (2). |
0a4db6dc MB |
431 | It can be used to uniquely identify a file on a filesystem and can be |
432 | passed as an argument to | |
817c8240 | 433 | .BR open_by_handle_at (2). |
0a4db6dc MB |
434 | Note that for directory entry events, such as |
435 | .BR FAN_CREATE , | |
436 | .BR FAN_DELETE , | |
817c8240 MK |
437 | and |
438 | .BR FAN_MOVE , | |
0a4db6dc MB |
439 | the |
440 | .IR file_handle | |
441 | describes the modified directory and not the created/deleted/moved child | |
442 | object. | |
443 | The events | |
444 | .BR FAN_ATTRIB , | |
817c8240 | 445 | .BR FAN_DELETE_SELF , |
0a4db6dc MB |
446 | and |
447 | .BR FAN_MOVE_SELF | |
448 | will carry the | |
449 | .IR file_handle | |
450 | information for the child object if the child object is being watched. | |
a93e5c95 AG |
451 | For the event |
452 | .BR FAN_DIR_MODIFY , | |
453 | the | |
454 | .I info_type | |
455 | field of this header is set to | |
456 | .BR FAN_EVENT_INFO_TYPE_DFID_NAME . | |
457 | The file handle describes the modified directory and a null terminated | |
458 | name of the modified entry follows directly after the file handle buffer. | |
0a4db6dc | 459 | .PP |
1b24e2ee | 460 | The following macros are provided to iterate over a buffer containing |
4a57583f | 461 | fanotify event metadata returned by a |
597aaea2 | 462 | .BR read (2) |
4a57583f | 463 | from an fanotify file descriptor: |
597aaea2 HS |
464 | .TP |
465 | .B FAN_EVENT_OK(meta, len) | |
466 | This macro checks the remaining length | |
467 | .I len | |
468 | of the buffer | |
469 | .I meta | |
470 | against the length of the metadata structure and the | |
471 | .I event_len | |
472 | field of the first metadata structure in the buffer. | |
473 | .TP | |
474 | .B FAN_EVENT_NEXT(meta, len) | |
98f7d53c | 475 | This macro uses the length indicated in the |
597aaea2 | 476 | .I event_len |
98f7d53c MK |
477 | field of the metadata structure pointed to by |
478 | .IR meta | |
479 | to calculate the address of the next metadata structure that follows | |
480 | .IR meta . | |
481 | .I len | |
482 | is the number of bytes of metadata that currently remain in the buffer. | |
483 | The macro returns a pointer to the next metadata structure that follows | |
484 | .IR meta , | |
485 | and reduces | |
486 | .I len | |
d721b5aa | 487 | by the number of bytes in the metadata structure that |
98f7d53c MK |
488 | has been skipped over (i.e., it subtracts |
489 | .IR meta\->event_len | |
490 | from | |
491 | .IR len ). | |
3c36e635 HS |
492 | .PP |
493 | In addition, there is: | |
494 | .TP | |
495 | .B FAN_EVENT_METADATA_LEN | |
7c0f0ce0 MK |
496 | This macro returns the size (in bytes) of the structure |
497 | .IR fanotify_event_metadata . | |
3c36e635 | 498 | This is the minimum size (and currently the only size) of any event metadata. |
98f7d53c | 499 | .\" |
488cdd81 MK |
500 | .SS Monitoring an fanotify file descriptor for events |
501 | When an fanotify event occurs, the fanotify file descriptor indicates as | |
502 | readable when passed to | |
503 | .BR epoll (7), | |
504 | .BR poll (2), | |
505 | or | |
506 | .BR select (2). | |
88145b29 | 507 | .SS Dealing with permission events |
597aaea2 HS |
508 | For permission events, the application must |
509 | .BR write (2) | |
510 | a structure of the following form to the | |
d3471a46 | 511 | fanotify file descriptor: |
a721e8b2 | 512 | .PP |
597aaea2 | 513 | .in +4n |
b8302363 | 514 | .EX |
597aaea2 HS |
515 | struct fanotify_response { |
516 | __s32 fd; | |
517 | __u32 response; | |
518 | }; | |
b8302363 | 519 | .EE |
597aaea2 | 520 | .in |
d7d24d40 MK |
521 | .PP |
522 | The fields of this structure are as follows: | |
9d76d630 | 523 | .TP |
597aaea2 HS |
524 | .I fd |
525 | This is the file descriptor from the structure | |
526 | .IR fanotify_event_metadata . | |
527 | .TP | |
528 | .I response | |
529 | This field indicates whether or not the permission is to be granted. | |
530 | Its value must be either | |
531 | .B FAN_ALLOW | |
532 | to allow the file operation or | |
533 | .B FAN_DENY | |
534 | to deny the file operation. | |
535 | .PP | |
49894a5a MK |
536 | If access is denied, the requesting application call will receive an |
537 | .BR EPERM | |
538 | error. | |
88145b29 | 539 | .SS Closing the fanotify file descriptor |
be8ba5d8 MK |
540 | .PP |
541 | When all file descriptors referring to the fanotify notification group are | |
542 | closed, the fanotify group is released and its resources | |
543 | are freed for reuse by the kernel. | |
544 | Upon | |
545 | .BR close (2), | |
546 | outstanding permission events will be set to allowed. | |
c00ff2dc | 547 | .SS /proc/[pid]/fdinfo |
597aaea2 | 548 | The file |
3d4433fe | 549 | .I /proc/[pid]/fdinfo/[fd] |
597aaea2 HS |
550 | contains information about fanotify marks for file descriptor |
551 | .I fd | |
552 | of process | |
553 | .IR pid . | |
75f8598a MK |
554 | See |
555 | .BR proc (5) | |
597aaea2 HS |
556 | for details. |
557 | .SH ERRORS | |
558 | In addition to the usual errors for | |
559 | .BR read (2), | |
1b24e2ee MK |
560 | the following errors can occur when reading from the |
561 | fanotify file descriptor: | |
597aaea2 HS |
562 | .TP |
563 | .B EINVAL | |
4a57583f | 564 | The buffer is too small to hold the event. |
597aaea2 HS |
565 | .TP |
566 | .B EMFILE | |
567 | The per-process limit on the number of open files has been reached. | |
568 | See the description of | |
569 | .B RLIMIT_NOFILE | |
570 | in | |
571 | .BR getrlimit (2). | |
572 | .TP | |
573 | .B ENFILE | |
e258766b | 574 | The system-wide limit on the total number of open files has been reached. |
597aaea2 | 575 | See |
fa6d3b26 | 576 | .I /proc/sys/fs/file\-max |
597aaea2 HS |
577 | in |
578 | .BR proc (5). | |
579 | .TP | |
580 | .B ETXTBSY | |
597aaea2 | 581 | This error is returned by |
68bcc008 | 582 | .BR read (2) |
597aaea2 HS |
583 | if |
584 | .B O_RDWR | |
585 | or | |
586 | .B O_WRONLY | |
587 | was specified in the | |
588 | .I event_f_flags | |
589 | argument when calling | |
590 | .BR fanotify_init (2) | |
68bcc008 | 591 | and an event occurred for a monitored file that is currently being executed. |
597aaea2 HS |
592 | .PP |
593 | In addition to the usual errors for | |
594 | .BR write (2), | |
595 | the following errors can occur when writing to the fanotify file descriptor: | |
596 | .TP | |
597 | .B EINVAL | |
1b24e2ee MK |
598 | Fanotify access permissions are not enabled in the kernel configuration |
599 | or the value of | |
597aaea2 HS |
600 | .I response |
601 | in the response structure is not valid. | |
602 | .TP | |
603 | .B ENOENT | |
604 | The file descriptor | |
605 | .I fd | |
606 | in the response structure is not valid. | |
33022419 MK |
607 | This may occur when a response for the permission event has already been |
608 | written. | |
597aaea2 HS |
609 | .SH VERSIONS |
610 | The fanotify API was introduced in version 2.6.36 of the Linux kernel and | |
611 | enabled in version 2.6.37. | |
612 | Fdinfo support was added in version 3.8. | |
d282bb24 | 613 | .SH CONFORMING TO |
597aaea2 HS |
614 | The fanotify API is Linux-specific. |
615 | .SH NOTES | |
616 | The fanotify API is available only if the kernel was built with the | |
617 | .B CONFIG_FANOTIFY | |
618 | configuration option enabled. | |
619 | In addition, fanotify permission handling is available only if the | |
620 | .B CONFIG_FANOTIFY_ACCESS_PERMISSIONS | |
621 | configuration option is enabled. | |
622 | .SS Limitations and caveats | |
623 | Fanotify reports only events that a user-space program triggers through the | |
624 | filesystem API. | |
1b24e2ee MK |
625 | As a result, |
626 | it does not catch remote events that occur on network filesystems. | |
597aaea2 HS |
627 | .PP |
628 | The fanotify API does not report file accesses and modifications that | |
629 | may occur because of | |
630 | .BR mmap (2), | |
631 | .BR msync (2), | |
632 | and | |
633 | .BR munmap (2). | |
634 | .PP | |
635 | Events for directories are created only if the directory itself is opened, | |
636 | read, and closed. | |
637 | Adding, removing, or changing children of a marked directory does not create | |
638 | events for the monitored directory itself. | |
639 | .PP | |
1b24e2ee MK |
640 | Fanotify monitoring of directories is not recursive: |
641 | to monitor subdirectories under a directory, | |
642 | additional marks must be created. | |
a93e5c95 AG |
643 | The |
644 | .B FAN_DIR_MODIFY | |
645 | event can be used for detecting when a subdirectory has been created under | |
646 | a marked directory. | |
647 | An additional mark must then be set on the newly created subdirectory. | |
597aaea2 | 648 | Monitoring mounts offers the capability to monitor a whole directory tree. |
b2f8214d AG |
649 | Monitoring filesystems offers the capability to monitor changes made from |
650 | any mount of a filesystem instance. | |
597aaea2 HS |
651 | .PP |
652 | The event queue can overflow. | |
653 | In this case, events are lost. | |
654 | .SH BUGS | |
707914e9 MK |
655 | Before Linux 3.19, |
656 | .BR fallocate (2) | |
657 | did not generate fanotify events. | |
658 | Since Linux 3.19, | |
659 | .\" commit 820c12d5d6c0890bc93dd63893924a13041fdc35 | |
660 | calls to | |
661 | .BR fallocate (2) | |
662 | generate | |
663 | .B FAN_MODIFY | |
664 | events. | |
a721e8b2 | 665 | .PP |
d5b26a69 | 666 | As of Linux 3.17, |
1aa556ab | 667 | the following bugs exist: |
597aaea2 | 668 | .IP * 3 |
c5a00024 | 669 | On Linux, a filesystem object may be accessible through multiple paths, |
8e38f6d3 | 670 | for example, a part of a filesystem may be remounted using the |
c5a00024 MK |
671 | .IR \-\-bind |
672 | option of | |
673 | .BR mount (8). | |
674 | A listener that marked a mount will be notified only of events that were | |
675 | triggered for a filesystem object using the same mount. | |
a4b394f2 HS |
676 | Any other event will pass unnoticed. |
677 | .IP * | |
bea08fec | 678 | .\" FIXME . A patch was proposed. |
1b24e2ee MK |
679 | When an event is generated, |
680 | no check is made to see whether the user ID of the | |
681 | receiving process has authorization to read or write the file | |
682 | before passing a file descriptor for that file. | |
597aaea2 HS |
683 | This poses a security risk, when the |
684 | .B CAP_SYS_ADMIN | |
685 | capability is set for programs executed by unprivileged users. | |
f96adfdc HS |
686 | .IP * |
687 | If a call to | |
1c612526 | 688 | .BR read (2) |
e1001916 MK |
689 | processes multiple events from the fanotify queue and an error occurs, |
690 | the return value will be the total length of the events successfully | |
691 | copied to the user-space buffer before the error occurred. | |
692 | The return value will not be \-1, and | |
f96adfdc HS |
693 | .I errno |
694 | will not be set. | |
e1001916 | 695 | Thus, the reading application has no way to detect the error. |
597aaea2 | 696 | .SH EXAMPLE |
0a4db6dc | 697 | The two example programs below demonstrate the usage of the fanotify API. |
3051b98c MK |
698 | .SS Example program: fanotify_example.c |
699 | The first program is an example of fanotify being | |
0a4db6dc MB |
700 | used with its event object information passed in the form of a file |
701 | descriptor. | |
3051b98c MK |
702 | The program marks the mount point passed as a command-line argument and |
703 | waits for events of type | |
6684e3e4 | 704 | .B FAN_OPEN_PERM |
597aaea2 HS |
705 | and |
706 | .BR FAN_CLOSE_WRITE . | |
707 | When a permission event occurs, a | |
708 | .B FAN_ALLOW | |
709 | response is given. | |
710 | .PP | |
3051b98c MK |
711 | The following shell session shows an example of |
712 | running this program. | |
0a4db6dc | 713 | This session involved editing the file |
597aaea2 HS |
714 | .IR /home/user/temp/notes . |
715 | Before the file was opened, a | |
716 | .B FAN_OPEN_PERM | |
717 | event occurred. | |
718 | After the file was closed, a | |
719 | .B FAN_CLOSE_WRITE | |
720 | event occurred. | |
721 | Execution of the program ends when the user presses the ENTER key. | |
0a4db6dc | 722 | .PP |
597aaea2 | 723 | .in +4n |
b8302363 | 724 | .EX |
26f6196a | 725 | # \fB./fanotify_example /home\fP |
597aaea2 HS |
726 | Press enter key to terminate. |
727 | Listening for events. | |
728 | FAN_OPEN_PERM: File /home/user/temp/notes | |
729 | FAN_CLOSE_WRITE: File /home/user/temp/notes | |
730 | ||
731 | Listening for events stopped. | |
b8302363 | 732 | .EE |
3051b98c | 733 | .in |
0a4db6dc | 734 | .SS Program source: fanotify_example.c |
c7885256 | 735 | \& |
e7d0bb47 | 736 | .EX |
616fce49 | 737 | #define _GNU_SOURCE /* Needed to get O_LARGEFILE definition */ |
597aaea2 HS |
738 | #include <errno.h> |
739 | #include <fcntl.h> | |
740 | #include <limits.h> | |
741 | #include <poll.h> | |
742 | #include <stdio.h> | |
743 | #include <stdlib.h> | |
744 | #include <sys/fanotify.h> | |
745 | #include <unistd.h> | |
746 | ||
5ff63f51 | 747 | /* Read all available fanotify events from the file descriptor \(aqfd\(aq */ |
597aaea2 | 748 | |
815df19b | 749 | static void |
597aaea2 HS |
750 | handle_events(int fd) |
751 | { | |
752 | const struct fanotify_event_metadata *metadata; | |
864eccb9 | 753 | struct fanotify_event_metadata buf[200]; |
597aaea2 HS |
754 | ssize_t len; |
755 | char path[PATH_MAX]; | |
756 | ssize_t path_len; | |
757 | char procfd_path[PATH_MAX]; | |
758 | struct fanotify_response response; | |
759 | ||
f7767949 | 760 | /* Loop while events can be read from fanotify file descriptor */ |
597aaea2 | 761 | |
7877c846 | 762 | for (;;) { |
597aaea2 | 763 | |
f7767949 | 764 | /* Read some events */ |
597aaea2 HS |
765 | |
766 | len = read(fd, (void *) &buf, sizeof(buf)); | |
767 | if (len == \-1 && errno != EAGAIN) { | |
768 | perror("read"); | |
769 | exit(EXIT_FAILURE); | |
770 | } | |
771 | ||
f7767949 | 772 | /* Check if end of available data reached */ |
597aaea2 HS |
773 | |
774 | if (len <= 0) | |
775 | break; | |
776 | ||
f7767949 | 777 | /* Point to the first event in the buffer */ |
597aaea2 | 778 | |
864eccb9 | 779 | metadata = buf; |
597aaea2 | 780 | |
f7767949 | 781 | /* Loop over all events in the buffer */ |
597aaea2 HS |
782 | |
783 | while (FAN_EVENT_OK(metadata, len)) { | |
784 | ||
f7767949 | 785 | /* Check that run\-time and compile\-time structures match */ |
597aaea2 HS |
786 | |
787 | if (metadata\->vers != FANOTIFY_METADATA_VERSION) { | |
788 | fprintf(stderr, | |
d1a71985 | 789 | "Mismatch of fanotify metadata version.\en"); |
597aaea2 HS |
790 | exit(EXIT_FAILURE); |
791 | } | |
792 | ||
bfff73cb MK |
793 | /* metadata\->fd contains either FAN_NOFD, indicating a |
794 | queue overflow, or a file descriptor (a nonnegative | |
795 | integer). Here, we simply ignore queue overflow. */ | |
0554d3f7 | 796 | |
597aaea2 HS |
797 | if (metadata\->fd >= 0) { |
798 | ||
f7767949 | 799 | /* Handle open permission event */ |
597aaea2 HS |
800 | |
801 | if (metadata\->mask & FAN_OPEN_PERM) { | |
802 | printf("FAN_OPEN_PERM: "); | |
803 | ||
f7767949 | 804 | /* Allow file to be opened */ |
597aaea2 HS |
805 | |
806 | response.fd = metadata\->fd; | |
807 | response.response = FAN_ALLOW; | |
f7767949 | 808 | write(fd, &response, |
864eccb9 | 809 | sizeof(struct fanotify_response)); |
597aaea2 HS |
810 | } |
811 | ||
f7767949 | 812 | /* Handle closing of writable file event */ |
597aaea2 | 813 | |
f7767949 | 814 | if (metadata\->mask & FAN_CLOSE_WRITE) |
597aaea2 | 815 | printf("FAN_CLOSE_WRITE: "); |
597aaea2 | 816 | |
b34cbc45 | 817 | /* Retrieve and print pathname of the accessed file */ |
597aaea2 HS |
818 | |
819 | snprintf(procfd_path, sizeof(procfd_path), | |
820 | "/proc/self/fd/%d", metadata\->fd); | |
821 | path_len = readlink(procfd_path, path, | |
822 | sizeof(path) \- 1); | |
823 | if (path_len == \-1) { | |
824 | perror("readlink"); | |
825 | exit(EXIT_FAILURE); | |
826 | } | |
827 | ||
5ff63f51 | 828 | path[path_len] = \(aq\e0\(aq; |
d1a71985 | 829 | printf("File %s\en", path); |
597aaea2 | 830 | |
f7767949 | 831 | /* Close the file descriptor of the event */ |
597aaea2 HS |
832 | |
833 | close(metadata\->fd); | |
597aaea2 HS |
834 | } |
835 | ||
48fd9fe0 | 836 | /* Advance to next event */ |
597aaea2 HS |
837 | |
838 | metadata = FAN_EVENT_NEXT(metadata, len); | |
839 | } | |
840 | } | |
841 | } | |
842 | ||
843 | int | |
844 | main(int argc, char *argv[]) | |
845 | { | |
846 | char buf; | |
847 | int fd, poll_num; | |
848 | nfds_t nfds; | |
849 | struct pollfd fds[2]; | |
850 | ||
f7767949 | 851 | /* Check mount point is supplied */ |
597aaea2 HS |
852 | |
853 | if (argc != 2) { | |
d1a71985 | 854 | fprintf(stderr, "Usage: %s MOUNT\en", argv[0]); |
597aaea2 HS |
855 | exit(EXIT_FAILURE); |
856 | } | |
857 | ||
d1a71985 | 858 | printf("Press enter key to terminate.\en"); |
597aaea2 | 859 | |
f7767949 | 860 | /* Create the file descriptor for accessing the fanotify API */ |
597aaea2 HS |
861 | |
862 | fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK, | |
863 | O_RDONLY | O_LARGEFILE); | |
864 | if (fd == \-1) { | |
865 | perror("fanotify_init"); | |
866 | exit(EXIT_FAILURE); | |
867 | } | |
868 | ||
f7767949 | 869 | /* Mark the mount for: |
597aaea2 | 870 | \- permission events before opening files |
f7767949 MK |
871 | \- notification events after closing a write\-enabled |
872 | file descriptor */ | |
597aaea2 HS |
873 | |
874 | if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, | |
943c52b7 | 875 | FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD, |
597aaea2 HS |
876 | argv[1]) == \-1) { |
877 | perror("fanotify_mark"); | |
597aaea2 HS |
878 | exit(EXIT_FAILURE); |
879 | } | |
880 | ||
f7767949 | 881 | /* Prepare for polling */ |
597aaea2 HS |
882 | |
883 | nfds = 2; | |
884 | ||
f7767949 | 885 | /* Console input */ |
597aaea2 HS |
886 | |
887 | fds[0].fd = STDIN_FILENO; | |
888 | fds[0].events = POLLIN; | |
889 | ||
f7767949 | 890 | /* Fanotify input */ |
597aaea2 HS |
891 | |
892 | fds[1].fd = fd; | |
893 | fds[1].events = POLLIN; | |
894 | ||
f7767949 | 895 | /* This is the loop to wait for incoming events */ |
597aaea2 | 896 | |
d1a71985 | 897 | printf("Listening for events.\en"); |
370359a7 | 898 | |
597aaea2 HS |
899 | while (1) { |
900 | poll_num = poll(fds, nfds, \-1); | |
901 | if (poll_num == \-1) { | |
e1ca5880 MK |
902 | if (errno == EINTR) /* Interrupted by a signal */ |
903 | continue; /* Restart poll() */ | |
904 | ||
905 | perror("poll"); /* Unexpected error */ | |
597aaea2 HS |
906 | exit(EXIT_FAILURE); |
907 | } | |
370359a7 | 908 | |
597aaea2 HS |
909 | if (poll_num > 0) { |
910 | if (fds[0].revents & POLLIN) { | |
911 | ||
f7767949 | 912 | /* Console input is available: empty stdin and quit */ |
597aaea2 | 913 | |
5ff63f51 | 914 | while (read(STDIN_FILENO, &buf, 1) > 0 && buf != \(aq\en\(aq) |
597aaea2 HS |
915 | continue; |
916 | break; | |
917 | } | |
370359a7 | 918 | |
597aaea2 HS |
919 | if (fds[1].revents & POLLIN) { |
920 | ||
f7767949 | 921 | /* Fanotify events are available */ |
597aaea2 HS |
922 | |
923 | handle_events(fd); | |
924 | } | |
925 | } | |
926 | } | |
927 | ||
d1a71985 | 928 | printf("Listening for events stopped.\en"); |
f7767949 | 929 | exit(EXIT_SUCCESS); |
597aaea2 | 930 | } |
e7d0bb47 | 931 | .EE |
3051b98c MK |
932 | .\" |
933 | .SS Example program: fanotify_fid.c | |
934 | The second program is an example of fanotify being used with | |
935 | .B FAN_REPORT_FID | |
936 | enabled. | |
794b5143 | 937 | The program marks the filesystem object that is passed as |
3051b98c MK |
938 | a command-line argument |
939 | and waits until an event of type | |
940 | .B FAN_CREATE | |
a93e5c95 AG |
941 | or |
942 | .B FAN_DIR_MODIFY | |
3051b98c | 943 | has occurred. |
794b5143 | 944 | The event mask indicates which type of filesystem object\(emeither |
8f397fb4 | 945 | a file or a directory\(emwas created. |
3051b98c MK |
946 | Once all events have been read from the buffer and processed accordingly, |
947 | the program simply terminates. | |
948 | .PP | |
949 | The following shell sessions show two different invocations of | |
950 | this program, with different actions performed on a watched object. | |
951 | .PP | |
952 | The first session shows a mark being placed on | |
953 | .IR /home/user . | |
954 | This is followed by the creation of a regular file, | |
955 | .IR /home/user/testfile.txt . | |
956 | This results in a | |
957 | .B FAN_CREATE | |
4e535185 | 958 | event being generated and reported against the file's parent watched |
a93e5c95 AG |
959 | directory object and a |
960 | .B FAN_DIR_MODIFY | |
961 | event being generated and reported with the created file name. | |
3051b98c MK |
962 | Program execution ends once all events captured within the buffer have |
963 | been processed. | |
3051b98c MK |
964 | .PP |
965 | .in +4n | |
966 | .EX | |
967 | # \fB./fanotify_fid /home/user\fP | |
968 | Listening for events. | |
4e535185 AG |
969 | FAN_CREATE (file created): |
970 | Directory /home/user has been modified. | |
a93e5c95 AG |
971 | FAN_DIR_MODIFY (entry changed): |
972 | Directory /home/user has been modified. | |
973 | Entry 'testfile.txt' is not a subdirectory. | |
3051b98c MK |
974 | All events processed successfully. Program exiting. |
975 | ||
4e535185 | 976 | $ \fBtouch /home/user/testfile.txt\fP # In another terminal |
3051b98c MK |
977 | .EE |
978 | .in | |
979 | .PP | |
980 | The second session shows a mark being placed on | |
981 | .IR /home/user . | |
982 | This is followed by the creation of a directory, | |
983 | .IR /home/user/testdir . | |
4e535185 | 984 | This specific action results in a |
3051b98c | 985 | .B FAN_CREATE |
4e535185 | 986 | event being generated and is reported with the |
3051b98c | 987 | .B FAN_ONDIR |
a93e5c95 AG |
988 | flag set and a |
989 | .B FAN_DIR_MODIFY | |
990 | event being generated and reported with the created directory name. | |
3051b98c MK |
991 | .PP |
992 | .in +4n | |
993 | .EX | |
994 | # \fB./fanotify_fid /home/user\fP | |
995 | Listening for events. | |
996 | FAN_CREATE | FAN_ONDIR (subdirectory created): | |
997 | Directory /home/user has been modified. | |
a93e5c95 AG |
998 | FAN_DIR_MODIFY (entry changed): |
999 | Directory /home/user has been modified. | |
1000 | Entry 'testdir' is a subdirectory. | |
3051b98c MK |
1001 | All events processed successfully. Program exiting. |
1002 | ||
4e535185 | 1003 | $ \fBmkdir \-p /home/user/testdir\fP # In another terminal |
3051b98c | 1004 | .EE |
0a4db6dc MB |
1005 | .in |
1006 | .SS Program source: fanotify_fid.c | |
1007 | \& | |
1008 | .EX | |
1009 | #define _GNU_SOURCE | |
1010 | #include <errno.h> | |
1011 | #include <fcntl.h> | |
1012 | #include <limits.h> | |
1013 | #include <stdio.h> | |
1014 | #include <stdlib.h> | |
1015 | #include <sys/types.h> | |
1016 | #include <sys/stat.h> | |
1017 | #include <sys/fanotify.h> | |
1018 | #include <unistd.h> | |
1019 | ||
1020 | #define BUF_SIZE 256 | |
1021 | ||
6f10bd32 MK |
1022 | int |
1023 | main(int argc, char **argv) | |
0a4db6dc | 1024 | { |
4e535185 | 1025 | int fd, ret, event_fd, mount_fd; |
0a4db6dc MB |
1026 | ssize_t len, path_len; |
1027 | char path[PATH_MAX]; | |
1028 | char procfd_path[PATH_MAX]; | |
1029 | char events_buf[BUF_SIZE]; | |
0a4db6dc MB |
1030 | struct file_handle *file_handle; |
1031 | struct fanotify_event_metadata *metadata; | |
1032 | struct fanotify_event_info_fid *fid; | |
a93e5c95 AG |
1033 | const char *file_name; |
1034 | struct stat sb; | |
0a4db6dc MB |
1035 | |
1036 | if (argc != 2) { | |
8f397fb4 | 1037 | fprintf(stderr, "Invalid number of command line arguments.\en"); |
0a4db6dc MB |
1038 | exit(EXIT_FAILURE); |
1039 | } | |
1040 | ||
4e535185 AG |
1041 | mount_fd = open(argv[1], O_DIRECTORY | O_RDONLY); |
1042 | if (mount_fd == \-1) { | |
1043 | perror(argv[1]); | |
1044 | exit(EXIT_FAILURE); | |
1045 | } | |
1046 | ||
1047 | ||
0a4db6dc | 1048 | /* Create an fanotify file descriptor with FAN_REPORT_FID as a flag |
87d12b1b MK |
1049 | so that program can receive fid events. */ |
1050 | ||
0a4db6dc | 1051 | fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_FID, 0); |
5ff63f51 | 1052 | if (fd == \-1) { |
0a4db6dc MB |
1053 | perror("fanotify_init"); |
1054 | exit(EXIT_FAILURE); | |
1055 | } | |
1056 | ||
1057 | /* Place a mark on the filesystem object supplied in argv[1]. */ | |
87d12b1b | 1058 | |
0a4db6dc | 1059 | ret = fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_ONLYDIR, |
a93e5c95 | 1060 | FAN_DIR_MODIFY | FAN_CREATE | FAN_ONDIR, |
0a4db6dc | 1061 | AT_FDCWD, argv[1]); |
5ff63f51 | 1062 | if (ret == \-1) { |
0a4db6dc MB |
1063 | perror("fanotify_mark"); |
1064 | exit(EXIT_FAILURE); | |
1065 | } | |
1066 | ||
8f397fb4 | 1067 | printf("Listening for events.\en"); |
0a4db6dc MB |
1068 | |
1069 | /* Read events from the event queue into a buffer */ | |
87d12b1b | 1070 | |
0a4db6dc | 1071 | len = read(fd, (void *) &events_buf, sizeof(events_buf)); |
5ff63f51 | 1072 | if (len == \-1 && errno != EAGAIN) { |
0a4db6dc MB |
1073 | perror("read"); |
1074 | exit(EXIT_FAILURE); | |
1075 | } | |
1076 | ||
1077 | /* Process all events within the buffer */ | |
87d12b1b | 1078 | |
0a4db6dc MB |
1079 | for (metadata = (struct fanotify_event_metadata *) events_buf; |
1080 | FAN_EVENT_OK(metadata, len); | |
1081 | metadata = FAN_EVENT_NEXT(metadata, len)) { | |
1082 | fid = (struct fanotify_event_info_fid *) (metadata + 1); | |
8f397fb4 | 1083 | file_handle = (struct file_handle *) fid\->handle; |
0a4db6dc MB |
1084 | |
1085 | /* Ensure that the event info is of the correct type */ | |
87d12b1b | 1086 | |
a93e5c95 AG |
1087 | if (fid\->hdr.info_type == FAN_EVENT_INFO_TYPE_FID) { |
1088 | file_name = NULL; | |
1089 | } else if (fid\->hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME) { | |
4c258dbc MK |
1090 | file_name = file_handle->f_handle + |
1091 | file_handle->handle_bytes; | |
a93e5c95 | 1092 | } else { |
8f397fb4 | 1093 | fprintf(stderr, "Received unexpected event info type.\en"); |
0a4db6dc MB |
1094 | exit(EXIT_FAILURE); |
1095 | } | |
1096 | ||
a93e5c95 AG |
1097 | if (metadata\->mask == FAN_DIR_MODIFY) |
1098 | printf("FAN_DIR_MODIFY (entry changed):\en"); | |
1099 | ||
8f397fb4 | 1100 | if (metadata\->mask == FAN_CREATE) |
4e535185 | 1101 | printf("FAN_CREATE (file created):\en"); |
0a4db6dc | 1102 | |
4e535185 AG |
1103 | if (metadata\->mask == (FAN_CREATE | FAN_ONDIR)) |
1104 | printf("FAN_CREATE | FAN_ONDIR (subdirectory created):\en"); | |
0a4db6dc | 1105 | |
4c258dbc MK |
1106 | /* metadata\->fd is set to FAN_NOFD when FAN_REPORT_FID is |
1107 | enabled. To obtain a file descriptor for the file object | |
1108 | corresponding to an event you can use the struct file_handle | |
1109 | that\(aqs provided within the fanotify_event_info_fid in | |
1110 | conjunction with the open_by_handle_at(2) system call. | |
1111 | A check for ESTALE is done to accommodate for the situation | |
1112 | where the file handle for the object was deleted prior to | |
1113 | this system call. */ | |
87d12b1b | 1114 | |
4e535185 AG |
1115 | event_fd = open_by_handle_at(mount_fd, file_handle, O_RDONLY); |
1116 | if (event_fd == \-1) { | |
2d26ddfa MK |
1117 | if (errno == ESTALE) { |
1118 | printf("File handle is no longer valid. " | |
8f397fb4 | 1119 | "File has been deleted\en"); |
2d26ddfa MK |
1120 | continue; |
1121 | } else { | |
1122 | perror("open_by_handle_at"); | |
1123 | exit(EXIT_FAILURE); | |
4e535185 | 1124 | } |
0a4db6dc MB |
1125 | } |
1126 | ||
6f10bd32 MK |
1127 | snprintf(procfd_path, sizeof(procfd_path), "/proc/self/fd/%d", |
1128 | event_fd); | |
0a4db6dc | 1129 | |
817c8240 | 1130 | /* Retrieve and print the path of the modified dentry */ |
87d12b1b | 1131 | |
5ff63f51 MK |
1132 | path_len = readlink(procfd_path, path, sizeof(path) \- 1); |
1133 | if (path_len == \-1) { | |
0a4db6dc MB |
1134 | perror("readlink"); |
1135 | exit(EXIT_FAILURE); | |
1136 | } | |
1137 | ||
8f397fb4 JW |
1138 | path[path_len] = \(aq\e0\(aq; |
1139 | printf("\etDirectory \(aq%s\(aq has been modified.\en", path); | |
0a4db6dc | 1140 | |
a93e5c95 AG |
1141 | if (file_name) { |
1142 | ret = fstatat(event_fd, file_name, &sb, 0); | |
1143 | if (ret == \-1) { | |
1144 | if (errno != ENOENT) { | |
1145 | perror("fstatat"); | |
1146 | exit(EXIT_FAILURE); | |
1147 | } | |
1148 | printf("\etEntry %\(aqs\(aq does not exist.\en", file_name); | |
1149 | } else if ((sb.st_mode & S_IFMT) == S_IFDIR) { | |
1150 | printf("\etEntry \(aq%s\(aq is a subdirectory.\en", file_name); | |
1151 | } else { | |
4c258dbc MK |
1152 | printf("\etEntry \(aq%s\(aq is not a subdirectory.\en", |
1153 | file_name); | |
a93e5c95 AG |
1154 | } |
1155 | } | |
1156 | ||
0a4db6dc | 1157 | /* Close associated file descriptor for this event */ |
5ff63f51 | 1158 | |
0a4db6dc MB |
1159 | close(event_fd); |
1160 | } | |
1161 | ||
8f397fb4 | 1162 | printf("All events processed successfully. Program exiting.\en"); |
0a4db6dc MB |
1163 | exit(EXIT_SUCCESS); |
1164 | } | |
1165 | .EE | |
d282bb24 | 1166 | .SH SEE ALSO |
597aaea2 HS |
1167 | .ad l |
1168 | .BR fanotify_init (2), | |
1169 | .BR fanotify_mark (2), | |
1170 | .BR inotify (7) |