]>
Commit | Line | Data |
---|---|---|
597aaea2 HS |
1 | .\" Copyright (C) 2013, Heinrich Schuchardt <xypron.glpk@gmx.de> |
2 | .\" | |
3 | .\" %%%LICENSE_START(VERBATIM) | |
4 | .\" Permission is granted to make and distribute verbatim copies of this | |
5 | .\" manual provided the copyright notice and this permission notice are | |
6 | .\" preserved on all copies. | |
7 | .\" | |
8 | .\" Permission is granted to copy and distribute modified versions of | |
9 | .\" this manual under the conditions for verbatim copying, provided that | |
10 | .\" the entire resulting derived work is distributed under the terms of | |
11 | .\" a permission notice identical to this one. | |
12 | .\" | |
13 | .\" Since the Linux kernel and libraries are constantly changing, this | |
14 | .\" manual page may be incorrect or out-of-date. The author(s) assume. | |
15 | .\" no responsibility for errors or omissions, or for damages resulting. | |
16 | .\" from the use of the information contained herein. The author(s) may. | |
17 | .\" not have taken the same level of care in the production of this. | |
18 | .\" manual, which is licensed free of charge, as they might when working. | |
19 | .\" professionally. | |
20 | .\" | |
21 | .\" Formatted or processed versions of this manual, if unaccompanied by | |
22 | .\" the source, must acknowledge the copyright and authors of this work. | |
23 | .\" %%%LICENSE_END | |
24 | .TH FANOTIFY 7 2014-04-24 "Linux" "Linux Programmer's Manual" | |
25 | .SH NAME | |
26 | fanotify \- monitoring filesystem events | |
27 | .SH DESCRIPTION | |
28 | The | |
29 | .B fanotify | |
30 | API provides notification and interception of filesystem events. | |
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.) | |
597aaea2 HS |
37 | |
38 | Additional capabilities compared to the | |
39 | .BR inotify (7) | |
40 | API are monitoring of complete mounts, access permission decisions, and the | |
41 | possibility to read or modify files before access by other applications. | |
42 | ||
43 | The following system calls are used with this API: | |
44 | .BR fanotify_init (2), | |
45 | .BR fanotify_mark (2), | |
46 | .BR poll (2), | |
47 | .BR ppoll (2), | |
48 | .BR read (2), | |
49 | .BR write (2), | |
50 | and | |
51 | .BR close (2). | |
88145b29 | 52 | .SS fanotify_init() 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 |
597aaea2 HS |
59 | a list of files, directories, and mount points for which events shall be |
60 | created. | |
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. | |
597aaea2 HS |
69 | Having these two types of masks permits a mount point or directory to be |
70 | marked for receiving events, while at the same time ignoring events for | |
71 | specific objects under that mount point or directory. | |
72 | .PP | |
73 | A possible usage of the ignore mask is for a file cache. | |
74 | Events of interest for a file cache are modification of a file and closing | |
75 | of the same. | |
76 | Hence, the cached directory or mount point is to be marked to receive these | |
77 | events. | |
78 | After receiving the first event informing that a file has been modified, the | |
79 | corresponding cache entry will be invalidated. | |
80 | No further modification events for this file are of interest until the file is | |
81 | closed. | |
82 | Hence, the modify event can be added to the ignore mask. | |
83 | Upon receiving the closed event, the modify event can be removed from the | |
84 | ignore mask and the file cache entry can be updated. | |
85 | .PP | |
86 | The entries in the fanotify notification groups refer to files and directories | |
87 | via their inode number and to mounts via their mount ID. | |
88 | If files or directories are renamed or moved, the respective entries survive. | |
89 | If files or directories are deleted or mounts are unmounted, the corresponding | |
90 | entries are deleted. | |
91 | .PP | |
92 | Two types of events exist: notification events and permission events. | |
93 | Notification events are only informative and require no action to be taken by | |
94 | the receiving application except for closing the file descriptor passed in the | |
95 | event. | |
96 | Permission events are requests to the receiving application to decide whether | |
97 | permission for a file access shall be granted. | |
98 | For these events, the recipient must write a response which decides whether | |
99 | access is granted or not. | |
100 | .PP | |
101 | When all file descriptors referring to the fanotify notification group are | |
102 | closed, the fanotify group is released and its resources are freed for reuse by | |
103 | the kernel. | |
88145b29 | 104 | .SS fanotify_mark() |
397ff1fd | 105 | The |
597aaea2 | 106 | .BR fanotify_mark (2) |
397ff1fd MK |
107 | system call adds a file, directory, or mount to the group |
108 | and specifies which events | |
597aaea2 | 109 | shall be reported (or ignored), or removes or modifies such an entry. |
88145b29 | 110 | .SS Events, the event queue, and reading events |
597aaea2 HS |
111 | When an fanotify event occurs, the fanotify file descriptor indicates as |
112 | readable when passed to | |
113 | .BR epoll (7), | |
114 | .BR poll (2), | |
115 | or | |
116 | .BR select (2). | |
117 | .PP | |
118 | All events for an fanotify group are collected in a queue. | |
119 | Consecutive events for the same filesystem object and originating from the | |
120 | same process may be merged into a single event, with the exception that two | |
121 | permission events are never merged into one queue entry. | |
122 | Queue entries for notification events are removed when the event has been | |
123 | read. | |
124 | Queue entries for permission events are removed when the permission | |
125 | decision has been taken by writing to the fanotify file descriptor. | |
126 | .PP | |
127 | Calling | |
128 | .BR read (2) | |
129 | for the file descriptor returned by | |
130 | .BR fanotify_init (2) | |
131 | blocks (if the flag | |
132 | .B FAN_NONBLOCK | |
133 | is not specified in the call to | |
134 | .BR fanotify_init (2)) | |
135 | until either a file event occurs or the call is interrupted by a signal | |
136 | (see | |
137 | .BR signal (7)). | |
138 | ||
139 | The return value of | |
140 | .BR read (2) | |
141 | is the length of the filled buffer, or \-1 in case of an error. | |
142 | After a successful | |
7ea227bd | 143 | .BR read (2), |
597aaea2 HS |
144 | the read buffer contains one or more of the following structures: |
145 | ||
146 | .in +4n | |
147 | .nf | |
148 | struct fanotify_event_metadata { | |
149 | __u32 event_len; | |
150 | __u8 vers; | |
151 | __u8 reserved; | |
152 | __u16 metadata_len; | |
153 | __aligned_u64 mask; | |
154 | __s32 fd; | |
155 | __s32 pid; | |
156 | }; | |
157 | .fi | |
158 | .in | |
159 | ||
9d76d630 | 160 | .TP |
597aaea2 HS |
161 | .I event_len |
162 | This is the length of the data for the current event and the offset to the next | |
163 | event in the buffer. | |
7ea227bd | 164 | In the current implementation, the value of |
597aaea2 HS |
165 | .I event_len |
166 | is always | |
167 | .BR FAN_EVENT_METADATA_LEN . | |
7ea227bd | 168 | In principle, the API design would allow to return variable-length structures. |
597aaea2 HS |
169 | Therefore, and for performance reasons, it is recommended to use a larger |
170 | buffer size when reading, for example 4096 bytes. | |
171 | .TP | |
172 | .I vers | |
6d8c5d01 | 173 | This field holds a version number for the structure. |
597aaea2 HS |
174 | It must be compared to |
175 | .B FANOTIFY_METADATA_VERSION | |
6d8c5d01 MK |
176 | to verify that the structures returned at runtime match |
177 | the structures defined at compile time. | |
597aaea2 HS |
178 | In case of a mismatch, the application should abandon trying to use the |
179 | fanotify file descriptor. | |
180 | .TP | |
181 | .I reserved | |
182 | This field is not used. | |
183 | .TP | |
184 | .I metadata_len | |
185 | This is the length of the structure. | |
186 | The field was introduced to facilitate the implementation of optional headers | |
187 | per event type. | |
188 | No such optional headers exist in the current implementation. | |
189 | .TP | |
190 | .I mask | |
191 | This is a bit mask describing the event. | |
192 | .TP | |
193 | .I fd | |
194 | This is an open file descriptor for the object being accessed, or | |
195 | .B FAN_NOFD | |
196 | if a queue overflow occurred. | |
197 | The file descriptor can be used to access the contents of the monitored file or | |
198 | directory. | |
6d8c5d01 | 199 | The |
597aaea2 | 200 | .B FMODE_NONOTIFY |
6d8c5d01 | 201 | file status flag is set on the corresponding open file description. |
597aaea2 HS |
202 | This flag suppresses fanotify event generation. |
203 | Hence, when the receiver of the fanotify event accesses the notified file or | |
204 | directory using this file descriptor, no additional events will be created. | |
205 | The reading application is responsible for closing the file descriptor. | |
206 | .TP | |
207 | .I pid | |
208 | This is the ID of the process that caused the event. | |
209 | A program listening to fanotify events can compare this PID to the PID returned | |
210 | by | |
211 | .BR getpid (2), | |
212 | to determine whether the event is caused by the listener itself, or is due to a | |
213 | file access by another program. | |
214 | .PP | |
215 | The bit mask in | |
216 | .I mask | |
217 | signals which events have occurred for a single filesystem object. | |
218 | More than one of the following flags can be set at once in the bit mask. | |
219 | .TP | |
220 | .B FAN_ACCESS | |
221 | A file or a directory (but see BUGS) was accessed (read). | |
222 | .TP | |
223 | .B FAN_OPEN | |
224 | A file or a directory was opened. | |
225 | .TP | |
226 | .B FAN_MODIFY | |
227 | A file was modified. | |
228 | .TP | |
229 | .B FAN_CLOSE_WRITE | |
230 | A file that was opened for writing | |
231 | .RB ( O_WRONLY | |
232 | or | |
233 | .BR O_RDWR ) | |
234 | was closed. | |
235 | .TP | |
236 | .B FAN_CLOSE_NOWRITE | |
02a18e0f | 237 | A file or directory that was opened read-only |
597aaea2 | 238 | .RB ( O_RDONLY ) |
02a18e0f | 239 | was closed. |
597aaea2 HS |
240 | .TP |
241 | .B FAN_Q_OVERFLOW | |
242 | The event queue exceeded the limit of 16384 entries. | |
243 | This limit can be overridden in the call to | |
244 | .BR fanotify_init (2) | |
245 | by setting the flag | |
246 | .BR FAN_UNLIMITED_QUEUE . | |
247 | .TP | |
248 | .B FAN_ACCESS_PERM | |
249 | An application wants to read a file or directory, for example using | |
250 | .BR read (2) | |
251 | or | |
252 | .BR readdir (2). | |
253 | The reader must write a response that determines whether the permission to | |
254 | access the filesystem object shall be granted. | |
255 | .TP | |
256 | .B FAN_OPEN_PERM | |
257 | An application wants to open a file or directory. | |
258 | The reader must write a response that determines whether the permission to | |
259 | open the filesystem object shall be granted. | |
260 | .PP | |
261 | To check for any close event, the following bit mask may be used: | |
262 | .TP | |
263 | .B FAN_CLOSE | |
264 | A file was closed | |
265 | (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE). | |
266 | .PP | |
267 | The following macros are provided to iterate over a buffer containing fanotify | |
6d8c5d01 | 268 | event metadata returned by a |
597aaea2 HS |
269 | .BR read (2) |
270 | from an fanotify file descriptor. | |
271 | .TP | |
272 | .B FAN_EVENT_OK(meta, len) | |
273 | This macro checks the remaining length | |
274 | .I len | |
275 | of the buffer | |
276 | .I meta | |
277 | against the length of the metadata structure and the | |
278 | .I event_len | |
279 | field of the first metadata structure in the buffer. | |
280 | .TP | |
281 | .B FAN_EVENT_NEXT(meta, len) | |
282 | This macro sets the pointer | |
283 | .I meta | |
284 | to the next metadata structure using the length indicated in the | |
285 | .I event_len | |
286 | field of the metadata structure and reduces the remaining length of the | |
287 | buffer | |
7ea227bd | 288 | .IR len . |
88145b29 | 289 | .SS Dealing with permission events |
597aaea2 HS |
290 | For permission events, the application must |
291 | .BR write (2) | |
292 | a structure of the following form to the | |
293 | .B fanotify | |
294 | file descriptor: | |
295 | ||
296 | .in +4n | |
297 | .nf | |
298 | struct fanotify_response { | |
299 | __s32 fd; | |
300 | __u32 response; | |
301 | }; | |
302 | .fi | |
303 | .in | |
304 | ||
9d76d630 | 305 | .TP |
597aaea2 HS |
306 | .I fd |
307 | This is the file descriptor from the structure | |
308 | .IR fanotify_event_metadata . | |
309 | .TP | |
310 | .I response | |
311 | This field indicates whether or not the permission is to be granted. | |
312 | Its value must be either | |
313 | .B FAN_ALLOW | |
314 | to allow the file operation or | |
315 | .B FAN_DENY | |
316 | to deny the file operation. | |
317 | .PP | |
318 | If access has been denied, the requesting application call will receive an | |
319 | error | |
320 | .BR EPERM . | |
88145b29 | 321 | .SS Closing the fanotify file descriptor |
597aaea2 HS |
322 | To end listening, it is sufficient to |
323 | .BR close (2) | |
324 | the fanotify file descriptor. | |
325 | The outstanding permission events will be set to allowed, and all resources | |
326 | will be returned to the kernel. | |
327 | .PP | |
328 | The file | |
329 | .I /proc/<pid>/fdinfo/<fd> | |
330 | contains information about fanotify marks for file descriptor | |
331 | .I fd | |
332 | of process | |
333 | .IR pid . | |
334 | See | |
335 | .I Documentation/filesystems/proc.txt | |
336 | for details. | |
337 | .SH ERRORS | |
338 | In addition to the usual errors for | |
339 | .BR read (2), | |
340 | the following errors can occur when reading from the fanotify file descriptor: | |
341 | .TP | |
342 | .B EINVAL | |
343 | The buffer is too short to hold the event. | |
344 | .TP | |
345 | .B EMFILE | |
346 | The per-process limit on the number of open files has been reached. | |
347 | See the description of | |
348 | .B RLIMIT_NOFILE | |
349 | in | |
350 | .BR getrlimit (2). | |
351 | .TP | |
352 | .B ENFILE | |
353 | The system-wide limit on the number of open files has been reached. | |
354 | See | |
355 | .I /proc/sys/fs/file-max | |
356 | in | |
357 | .BR proc (5). | |
358 | .TP | |
359 | .B ETXTBSY | |
360 | A write enabled file descriptor shall be created for a file that is executing. | |
361 | This error is returned by | |
362 | .BR read (2), | |
363 | if | |
364 | .B O_RDWR | |
365 | or | |
366 | .B O_WRONLY | |
367 | was specified in the | |
368 | .I event_f_flags | |
369 | argument when calling | |
370 | .BR fanotify_init (2) | |
8d2ee5c8 | 371 | and the event occurred for a monitored file that is currently being executed. |
597aaea2 HS |
372 | .PP |
373 | In addition to the usual errors for | |
374 | .BR write (2), | |
375 | the following errors can occur when writing to the fanotify file descriptor: | |
376 | .TP | |
377 | .B EINVAL | |
378 | Fanotify access permissions are not enabled in the kernel configuration or the | |
379 | value of | |
380 | .I response | |
381 | in the response structure is not valid. | |
382 | .TP | |
383 | .B ENOENT | |
384 | The file descriptor | |
385 | .I fd | |
386 | in the response structure is not valid. | |
387 | This might occur because the file was already deleted by another thread or | |
388 | process. | |
389 | .SH VERSIONS | |
390 | The fanotify API was introduced in version 2.6.36 of the Linux kernel and | |
391 | enabled in version 2.6.37. | |
392 | Fdinfo support was added in version 3.8. | |
393 | .SH "CONFORMING TO" | |
394 | The fanotify API is Linux-specific. | |
395 | .SH NOTES | |
396 | The fanotify API is available only if the kernel was built with the | |
397 | .B CONFIG_FANOTIFY | |
398 | configuration option enabled. | |
399 | In addition, fanotify permission handling is available only if the | |
400 | .B CONFIG_FANOTIFY_ACCESS_PERMISSIONS | |
401 | configuration option is enabled. | |
402 | .SS Limitations and caveats | |
403 | Fanotify reports only events that a user-space program triggers through the | |
404 | filesystem API. | |
405 | As a result, it does not catch remote events that occur on network filesystems. | |
406 | .PP | |
407 | The fanotify API does not report file accesses and modifications that | |
408 | may occur because of | |
409 | .BR mmap (2), | |
410 | .BR msync (2), | |
411 | and | |
412 | .BR munmap (2). | |
413 | .PP | |
414 | Events for directories are created only if the directory itself is opened, | |
415 | read, and closed. | |
416 | Adding, removing, or changing children of a marked directory does not create | |
417 | events for the monitored directory itself. | |
418 | .PP | |
419 | Fanotify monitoring of directories is not recursive: to monitor subdirectories | |
420 | under a directory, additional marks must be created. | |
421 | (But note that the fanotify API provides no way of detecting when a | |
422 | subdirectory has been created under a marked directory, which makes recursive | |
423 | monitoring difficult.) | |
424 | Monitoring mounts offers the capability to monitor a whole directory tree. | |
425 | .PP | |
426 | The event queue can overflow. | |
427 | In this case, events are lost. | |
428 | .SH BUGS | |
429 | As of Linux 3.15, | |
ddb112c2 | 430 | the following bugs exist: |
597aaea2 HS |
431 | .IP * 3 |
432 | .\" FIXME: Patch is in linux-next-20140424. | |
433 | .BR readdir (2) | |
434 | does not create a | |
435 | .B FAN_ACCESS | |
436 | event. | |
437 | .IP * | |
438 | .\" FIXME: A patch was proposed. | |
439 | When an event is generated, no check is made to see whether the user ID of the | |
440 | receiving process has authorization to read or write the file before passing a | |
441 | file descriptor for that file in | |
442 | This poses a security risk, when the | |
443 | .B CAP_SYS_ADMIN | |
444 | capability is set for programs executed by unprivileged users. | |
445 | .SH EXAMPLE | |
446 | The following program demonstrates the usage of the fanotify API. | |
ddb112c2 MK |
447 | It marks the mount point passed as command-line argument |
448 | and waits for events of type | |
597aaea2 HS |
449 | .B FAN_PERM_OPEN |
450 | and | |
451 | .BR FAN_CLOSE_WRITE . | |
452 | When a permission event occurs, a | |
453 | .B FAN_ALLOW | |
454 | response is given. | |
455 | .PP | |
ddb112c2 | 456 | The following output was recorded while editing the file |
597aaea2 HS |
457 | .IR /home/user/temp/notes . |
458 | Before the file was opened, a | |
459 | .B FAN_OPEN_PERM | |
460 | event occurred. | |
461 | After the file was closed, a | |
462 | .B FAN_CLOSE_WRITE | |
463 | event occurred. | |
464 | Execution of the program ends when the user presses the ENTER key. | |
465 | .SS Example output | |
466 | .in +4n | |
467 | .nf | |
468 | # ./fanotify_example /home | |
469 | Press enter key to terminate. | |
470 | Listening for events. | |
471 | FAN_OPEN_PERM: File /home/user/temp/notes | |
472 | FAN_CLOSE_WRITE: File /home/user/temp/notes | |
473 | ||
474 | Listening for events stopped. | |
475 | .fi | |
476 | .in | |
477 | .SS Program source | |
478 | .nf | |
8d2ee5c8 | 479 | #define _GNU_SOURCE /* Needed to get O_LARGEFILE definition */ |
597aaea2 HS |
480 | #include <errno.h> |
481 | #include <fcntl.h> | |
482 | #include <limits.h> | |
483 | #include <poll.h> | |
484 | #include <stdio.h> | |
485 | #include <stdlib.h> | |
486 | #include <sys/fanotify.h> | |
487 | #include <unistd.h> | |
488 | ||
489 | /* Read all available fanotify events from the file descriptor 'fd' */ | |
490 | ||
815df19b | 491 | static void |
597aaea2 HS |
492 | handle_events(int fd) |
493 | { | |
494 | const struct fanotify_event_metadata *metadata; | |
495 | char buf[4096]; | |
496 | ssize_t len; | |
497 | char path[PATH_MAX]; | |
498 | ssize_t path_len; | |
499 | char procfd_path[PATH_MAX]; | |
500 | struct fanotify_response response; | |
501 | ||
f7767949 | 502 | /* Loop while events can be read from fanotify file descriptor */ |
597aaea2 HS |
503 | |
504 | for(;;) { | |
505 | ||
f7767949 | 506 | /* Read some events */ |
597aaea2 HS |
507 | |
508 | len = read(fd, (void *) &buf, sizeof(buf)); | |
509 | if (len == \-1 && errno != EAGAIN) { | |
510 | perror("read"); | |
511 | exit(EXIT_FAILURE); | |
512 | } | |
513 | ||
f7767949 | 514 | /* Check if end of available data reached */ |
597aaea2 HS |
515 | |
516 | if (len <= 0) | |
517 | break; | |
518 | ||
f7767949 | 519 | /* Point to the first event in the buffer */ |
597aaea2 HS |
520 | |
521 | metadata = (struct fanotify_event_metadata *) buf; | |
522 | ||
f7767949 | 523 | /* Loop over all events in the buffer */ |
597aaea2 HS |
524 | |
525 | while (FAN_EVENT_OK(metadata, len)) { | |
526 | ||
f7767949 | 527 | /* Check that run\-time and compile\-time structures match */ |
597aaea2 HS |
528 | |
529 | if (metadata\->vers != FANOTIFY_METADATA_VERSION) { | |
530 | fprintf(stderr, | |
531 | "Mismatch of fanotify metadata version.\\n"); | |
532 | exit(EXIT_FAILURE); | |
533 | } | |
534 | ||
f7767949 | 535 | /* Check that the event contains a file descriptor */ |
597aaea2 HS |
536 | |
537 | if (metadata\->fd >= 0) { | |
538 | ||
f7767949 | 539 | /* Handle open permission event */ |
597aaea2 HS |
540 | |
541 | if (metadata\->mask & FAN_OPEN_PERM) { | |
542 | printf("FAN_OPEN_PERM: "); | |
543 | ||
f7767949 | 544 | /* Allow file to be opened */ |
597aaea2 HS |
545 | |
546 | response.fd = metadata\->fd; | |
547 | response.response = FAN_ALLOW; | |
f7767949 MK |
548 | write(fd, &response, |
549 | sizeof(struct fanotify_response)); | |
597aaea2 HS |
550 | } |
551 | ||
f7767949 | 552 | /* Handle closing of writable file event */ |
597aaea2 | 553 | |
f7767949 | 554 | if (metadata\->mask & FAN_CLOSE_WRITE) |
597aaea2 | 555 | printf("FAN_CLOSE_WRITE: "); |
597aaea2 | 556 | |
b34cbc45 | 557 | /* Retrieve and print pathname of the accessed file */ |
597aaea2 HS |
558 | |
559 | snprintf(procfd_path, sizeof(procfd_path), | |
560 | "/proc/self/fd/%d", metadata\->fd); | |
561 | path_len = readlink(procfd_path, path, | |
562 | sizeof(path) \- 1); | |
563 | if (path_len == \-1) { | |
564 | perror("readlink"); | |
565 | exit(EXIT_FAILURE); | |
566 | } | |
567 | ||
568 | path[path_len] = '\\0'; | |
def5c668 | 569 | printf("File %s\\n", path); |
597aaea2 | 570 | |
f7767949 | 571 | /* Close the file descriptor of the event */ |
597aaea2 HS |
572 | |
573 | close(metadata\->fd); | |
597aaea2 HS |
574 | } |
575 | ||
48fd9fe0 | 576 | /* Advance to next event */ |
597aaea2 HS |
577 | |
578 | metadata = FAN_EVENT_NEXT(metadata, len); | |
579 | } | |
580 | } | |
581 | } | |
582 | ||
583 | int | |
584 | main(int argc, char *argv[]) | |
585 | { | |
586 | char buf; | |
587 | int fd, poll_num; | |
588 | nfds_t nfds; | |
589 | struct pollfd fds[2]; | |
590 | ||
f7767949 | 591 | /* Check mount point is supplied */ |
597aaea2 HS |
592 | |
593 | if (argc != 2) { | |
f7767949 | 594 | fprintf(stderr, "Usage: %s MOUNT\\n", argv[0]); |
597aaea2 HS |
595 | exit(EXIT_FAILURE); |
596 | } | |
597 | ||
598 | printf("Press enter key to terminate.\\n"); | |
599 | ||
f7767949 | 600 | /* Create the file descriptor for accessing the fanotify API */ |
597aaea2 HS |
601 | |
602 | fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK, | |
603 | O_RDONLY | O_LARGEFILE); | |
604 | if (fd == \-1) { | |
605 | perror("fanotify_init"); | |
606 | exit(EXIT_FAILURE); | |
607 | } | |
608 | ||
f7767949 | 609 | /* Mark the mount for: |
597aaea2 | 610 | \- permission events before opening files |
f7767949 MK |
611 | \- notification events after closing a write\-enabled |
612 | file descriptor */ | |
597aaea2 HS |
613 | |
614 | if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, | |
615 | FAN_OPEN_PERM | FAN_CLOSE_WRITE, \-1, | |
616 | argv[1]) == \-1) { | |
617 | perror("fanotify_mark"); | |
597aaea2 HS |
618 | exit(EXIT_FAILURE); |
619 | } | |
620 | ||
f7767949 | 621 | /* Prepare for polling */ |
597aaea2 HS |
622 | |
623 | nfds = 2; | |
624 | ||
f7767949 | 625 | /* Console input */ |
597aaea2 HS |
626 | |
627 | fds[0].fd = STDIN_FILENO; | |
628 | fds[0].events = POLLIN; | |
629 | ||
f7767949 | 630 | /* Fanotify input */ |
597aaea2 HS |
631 | |
632 | fds[1].fd = fd; | |
633 | fds[1].events = POLLIN; | |
634 | ||
f7767949 | 635 | /* This is the loop to wait for incoming events */ |
597aaea2 HS |
636 | |
637 | printf("Listening for events.\\n"); | |
638 | while (1) { | |
639 | poll_num = poll(fds, nfds, \-1); | |
640 | if (poll_num == \-1) { | |
641 | if (errno == EINTR) | |
642 | continue; | |
643 | perror("poll"); | |
644 | exit(EXIT_FAILURE); | |
645 | } | |
646 | if (poll_num > 0) { | |
647 | if (fds[0].revents & POLLIN) { | |
648 | ||
f7767949 | 649 | /* Console input is available: empty stdin and quit */ |
597aaea2 HS |
650 | |
651 | while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\\n') | |
652 | continue; | |
653 | break; | |
654 | } | |
655 | if (fds[1].revents & POLLIN) { | |
656 | ||
f7767949 | 657 | /* Fanotify events are available */ |
597aaea2 HS |
658 | |
659 | handle_events(fd); | |
660 | } | |
661 | } | |
662 | } | |
663 | ||
597aaea2 | 664 | printf("Listening for events stopped.\\n"); |
f7767949 | 665 | exit(EXIT_SUCCESS); |
597aaea2 HS |
666 | } |
667 | .fi | |
668 | .SH "SEE ALSO" | |
669 | .ad l | |
670 | .BR fanotify_init (2), | |
671 | .BR fanotify_mark (2), | |
672 | .BR inotify (7) |