Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I program for Linux's new `fanotify` file system monitoring feature?

fanotify, built on top of fsnotify, is supposed to replace inotify which replaced dnotify. Are there some good programming examples or existing utilities that use fanotify to watch for changes in a filesystem? How much detail does fanotify provide?

like image 290
joeforker Avatar asked Dec 02 '09 21:12

joeforker


People also ask

How do you use Fanotify?

Fanotify monitoring of directories is not recursive: to monitor subdirectories under a directory, additional marks must be created. The FAN_CREATE event can be used for detecting when a subdirectory has been created under a marked directory. An additional mark must then be set on the newly created subdirectory.

What is Fanotify mode?

Fanotify is a file access notification system built in on many common Linux kernels. This kernel feature allows Sophos Anti-Virus to scan files on access and, if necessary, block access to threats.


3 Answers

This LWN article is often quoted as a source of documentation for fanotify. But the description there appears to be out of date. fanotify no longer works using a socket connection. Instead, there are two new libc functions wrapping syscalls, declared in sys/fanotify.h. One is called fanotify_init, the other is fanotify_mark. At the time of this writing, these syscalls are still included in the list of missing manual pages. There is, however, a mail containing drafts for these manual pages. With a combination of these man pages, a look at the headers in question, and a bit of trial and error, you should be able to get this going.

It seems that some of the functionality originally envisioned for fanotify is no longer suipported in that fashion. For example, the LWN article describes a FAN_GLOBAL_LISTENER flag which will implicitely mark the whole filesystem tree unless parts are explicitely unmarked. The current interface has no such provision, but a similar result can be achieved using the following mark:

fanotify_mark(fan,
              FAN_MARK_ADD | FAN_MARK_MOUNT,
              FAN_OPEN | FAN_EVENT_ON_CHILD,
              AT_FDCWD, "/")

Where inotify events provide the path to the accessed object as part of the event, fanotify opens a file descriptor for it. In order to turn this descriptor into a path name, the corresponding entry from the proc file system can be used, as described here.

Here is a simple example which simply prints the name of every opened file:

#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/fanotify.h>
#include <sys/stat.h>
#include <sys/types.h>
#define CHK(expr, errcode) if((expr)==errcode) perror(#expr), exit(EXIT_FAILURE)
int main(int argc, char** argv) {
  int fan;
  char buf[4096];
  char fdpath[32];
  char path[PATH_MAX + 1];
  ssize_t buflen, linklen;
  struct fanotify_event_metadata *metadata;
  CHK(fan = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY), -1);
  CHK(fanotify_mark(fan, FAN_MARK_ADD | FAN_MARK_MOUNT,
                    FAN_OPEN | FAN_EVENT_ON_CHILD, AT_FDCWD, "/"), -1);
  for (;;) {
    CHK(buflen = read(fan, buf, sizeof(buf)), -1);
    metadata = (struct fanotify_event_metadata*)&buf;
    while(FAN_EVENT_OK(metadata, buflen)) {
      if (metadata->mask & FAN_Q_OVERFLOW) {
        printf("Queue overflow!\n");
        continue;
      }
      sprintf(fdpath, "/proc/self/fd/%d", metadata->fd);
      CHK(linklen = readlink(fdpath, path, sizeof(path) - 1), -1);
      path[linklen] = '\0';
      printf("%s opened by process %d.\n", path, (int)metadata->pid);
      close(metadata->fd);
      metadata = FAN_EVENT_NEXT(metadata, buflen);
    }
  }
}
like image 139
MvG Avatar answered Nov 24 '22 16:11

MvG


The documentation for the fanotify API is available in the Linux manpages:

  • fanotify.7 - http://man7.org/linux/man-pages/man7/fanotify.7.html
  • fanotify_init.2 - http://man7.org/linux/man-pages/man2/fanotify_init.2.html
  • fanotify_mark.2 - http://man7.org/linux/man-pages/man2/fanotify_mark.2.html

Here are some examples, fatrace being the most elaborate.

  • https://launchpad.net/fatrace
  • http://git.infradead.org/users/eparis/fanotify-example.git
  • http://www.lanedo.com/~aleksander/fanotify/fanotify-example.c

Bindings exist for Go and Python.

like image 23
Tobu Avatar answered Nov 24 '22 16:11

Tobu


I just learned about fanotify and it seems very nice. Very nice interface!

It is not in the Linus tree yet but I guess it will get there for Linux 2.6.33 and before for testing (I noticed some patches today in LKML). In the original patch they announce a GIT tree thus you might be able to build a testing kernel from there. You might also find testing git trees.

I couldn't find utilities that use it but I guess they'll come soon.

There is an example here, at the end of the email:

http://lwn.net/Articles/339253/

If you are really interested in this new feature you might want to monitor the Linux Kernel Mailing List and interact there. You can also wait until the utilities are released or develop your own.

About the detail, it seems fanotify provides less events than inotify. I guess this might change in the future but since this is a brand new feature in development there is not much I can say about it now.

like image 39
arhuaco Avatar answered Nov 24 '22 14:11

arhuaco