1

I need to watch a directory with several subdirectories, each of which has files which I need to monitor for file additions, modifications and deletions.

I found some example code, and had to modify it slightly to get it working, but it doesn't exactly do what I need. It can find a file rename, or delete within a directory (but not a subdirectory), but doesn't respond to file modifications.

The way that I can find using a Google search is to monitor each file individually; however, I have several hundreds of thousands of files to monitor, and holding a file descriptor to each is probably unwise.

Is there a way under FreeBSD to do what I need to do? Or will I have to find an alternative solution?

#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h> 
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> 

int main(void) {
   int f, kq, nev;
   struct kevent change;
   struct kevent event;

   kq = kqueue();
   if (kq == -1)
       perror("kqueue");

   f = open("/tmp/foo", O_RDONLY);
   if (f == -1)
       perror("open");

   EV_SET(&change, f, EVFILT_VNODE,
          EV_ADD | EV_ENABLE | EV_ONESHOT,
          NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB,
          0, 0);

   for (;;) {
       nev = kevent(kq, &change, 1, &event, 1, NULL);
       if (nev == -1)
           perror("kevent");
       else if (nev > 0) {
           if (event.fflags & NOTE_DELETE) {
               printf("File deleted\n");
               break;
           }
           if (event.fflags & NOTE_EXTEND ||
               event.fflags & NOTE_WRITE)
               printf("File modified\n");
           if (event.fflags & NOTE_ATTRIB)
               printf("File attributes modified\n");
       }
   }

   close(kq);
   close(f);
   return EXIT_SUCCESS;
}
OmnipotentEntity
  • 16,531
  • 6
  • 62
  • 96

1 Answers1

3

As you rightly guessed, kqueue is not scalable because you have to hold a handle to the file / directory in question, even if in O_RDONLY mode. On Linux, one would use inotify for this purpose (http://linux.die.net/man/7/inotify), but I believe there is no FreeBSD port of this kernel feature!

If you have the time and resources, what you could do is look at the code for audit on BSD (http://www.freebsd.org/cgi/man.cgi?query=audit&sektion=4) and try to code up a version of inotify for BSD! O_O

vijucat
  • 2,059
  • 1
  • 15
  • 17
  • I don't think this'd be any easier with inotify. Inotify isn't recursive either, you'd still have monitor each file inidividually. The audit framework is a good suggestion though. Perhaps even dtrace might be useful here. – Kristof Provost Dec 24 '13 at 16:18
  • Do you know if usage of `audit` would require opening `fd`s to each monitored file. Also at @KristofProvost, I didn't know it wasn't recursive, if a recursive solution is required, that's cool. The major problem is holding all of those file descriptors. – OmnipotentEntity Dec 25 '13 at 17:16
  • Also Merry Christmas. :D – OmnipotentEntity Dec 25 '13 at 17:17
  • Merry Christmas, too! (But then you are an OmnipotentEntity, so maybe I should say : "Thank you for Christmas!"? :-) ). – vijucat Dec 25 '13 at 17:54
  • I'm 90% sure that the auditing mechanism does not require opening fds because it basically works inside the kernel (mostly) and logs syscalls. For example, if someone calls chmod() on a file that you are monitoring, the kernel code of chmod() itself does the logging. I suppose the real questions now are: a) how resource-intensive is it? and b) how easy is it to setup recursive directory monitoring? Let me know if you want me to dig up / help. – vijucat Dec 25 '13 at 18:02
  • Just thanks so much for the pointer. I'll look into it. If I develop anything nice I'll throw it on github or something. – OmnipotentEntity Dec 26 '13 at 05:49