
--- fam-2.7.0/configure.ac	2003-11-26 14:47:59.000000000 -0500
+++ fam-2.7.0-patched/configure.ac	2007-01-02 13:22:13.000000000 -0500
@@ -31,7 +31,7 @@
 # Checks for header files.
 AC_HEADER_STDC
 AC_HEADER_DIRENT
-AC_CHECK_HEADERS([fcntl.h limits.h linux/imon.h netinet/in.h rpc/rpc.h rpcsvc/mount.h stddef.h stdlib.h string.h syslog.h sys/imon.h sys/param.h sys/select.h sys/statvfs.h sys/syssgi.h sys/time.h sys/types.h sys/un.h unistd.h])
+AC_CHECK_HEADERS([fcntl.h limits.h linux/imon.h netinet/in.h rpc/rpc.h rpc/rpcent.h rpcsvc/mount.h stddef.h stdlib.h string.h syslog.h sys/filio.h sys/imon.h sys/param.h sys/select.h sys/statvfs.h sys/syssgi.h sys/time.h sys/types.h sys/un.h unistd.h mntent.h sys/mnttab.h sys/sysmacros.h])
 
 if test "$have_sys_imon_h"; then
 	MONITOR_FUNCS=IMonIRIX
@@ -51,12 +51,14 @@
 AC_TYPE_PID_T
 AC_TYPE_SIZE_T
 AC_HEADER_TIME
-AC_CHECK_MEMBERS(struct sockaddr.sa_len, struct sockaddr_un.sun_len)
+AC_CHECK_MEMBERS(struct sockaddr.sa_len,,,[#include <sys/socket.h>])
+AC_CHECK_MEMBERS(struct sockaddr_un.sun_len,,,[#include <sys/types.h>
+#include <sys/un.h>])
 
 # Checks for library functions.
 AC_FUNC_ERROR_AT_LINE
 AC_FUNC_SELECT_ARGTYPES
-AC_CHECK_FUNCS([bindresvport _daemonize daemon getgrmember select])
+AC_CHECK_FUNCS([bindresvport _daemonize daemon getgrmember select unsetenv])
 
 AC_CONFIG_FILES([Makefile
                  src/Makefile
--- fam-2.7.0/include/BTree.h	2003-01-19 23:22:30.000000000 -0500
+++ fam-2.7.0-patched/include/BTree.h	2007-01-02 13:22:14.000000000 -0500
@@ -76,8 +76,6 @@
 
     static unsigned sizeofnode()	{ return sizeof (Node); }
 
-private:
-
     enum { fanout = 32 };
     enum Status { OK, NO, OVER, UNDER };
 
--- fam-2.7.0/lib/Client.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/lib/Client.c++	2007-01-02 13:22:14.000000000 -0500
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #include <sys/un.h>
 #include <sys/socket.h>
 #include <rpc/rpc.h>
--- fam-2.7.0/lib/fam.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/lib/fam.c++	2007-01-02 13:22:14.000000000 -0500
@@ -20,8 +20,12 @@
 //  with this program; if not, write the Free Software Foundation, Inc., 59
 //  Temple Place - Suite 330, Boston MA 02111-1307, USA.
 
+#include "config.h"
 #include <sys/types.h>
 #include <rpc/rpc.h>
+#ifdef HAVE_RPC_RPCENT_H
+#include <rpc/rpcent.h>
+#endif
 #include <sys/time.h>
 #include <unistd.h>
 #include <stdlib.h>
--- fam-2.7.0/src/Client.h	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/Client.h	2007-01-02 13:22:14.000000000 -0500
@@ -25,6 +25,7 @@
 
 #include <sys/types.h>
 #include <netinet/in.h>  // for in_addr
+#include <arpa/inet.h>
 
 #include "Activity.h"
 #include "Boolean.h"
--- fam-2.7.0/src/FileSystem.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/FileSystem.c++	2007-01-02 13:22:13.000000000 -0500
@@ -22,14 +22,20 @@
 
 #include "FileSystem.h"
 
-#include <mntent.h>
+#include "fam-mntent.h"
 #include <string.h>
 
 #include "Event.h"
 
+#if defined(HAVE_SYS_MNTTAB_H)
+FileSystem::FileSystem(const mnttab& mnt)
+    : mydir   (strcpy(new char[strlen(mnt.mnt_mountp) + 1], mnt.mnt_mountp)),
+      myfsname(strcpy(new char[strlen(mnt.mnt_special) + 1], mnt.mnt_special))
+#else
 FileSystem::FileSystem(const mntent& mnt)
     : mydir   (strcpy(new char[strlen(mnt.mnt_dir   ) + 1], mnt.mnt_dir   )),
       myfsname(strcpy(new char[strlen(mnt.mnt_fsname) + 1], mnt.mnt_fsname))
+#endif
 { }
 
 FileSystem::~FileSystem()
@@ -40,9 +46,15 @@
 }
 
 bool
+#if defined(HAVE_SYS_MNTTAB_H)
+FileSystem::matches(const mnttab& mnt) const
+{
+    return !strcmp(mydir, mnt.mnt_mountp) && !strcmp(myfsname, mnt.mnt_special);
+#else
 FileSystem::matches(const mntent& mnt) const
 {
     return !strcmp(mydir, mnt.mnt_dir) && !strcmp(myfsname, mnt.mnt_fsname);
+#endif
 }
 
 void
--- fam-2.7.0/src/FileSystem.h	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/FileSystem.h	2007-01-02 13:22:14.000000000 -0500
@@ -27,7 +27,13 @@
 #include "Request.h"
 #include "Set.h"
 
+#include "fam-mntent.h"
+
+#if defined(HAVE_SYS_MNTTAB_H)
+struct mnttab;
+#else
 struct mntent;
+#endif
 struct stat;
 
 //  FileSystem is the abstract base class for a per-filesystem object.
@@ -91,12 +97,20 @@
 
     typedef Set<ClientInterest *> Interests;
 
+#if defined(HAVE_SYS_MNTTAB_H)
+    FileSystem(const mnttab&);
+#else
     FileSystem(const mntent&);
+#endif
     virtual ~FileSystem();
 
     //  Miscellaneous routines
 
+#if defined(HAVE_SYS_MNTTAB_H)
+    bool matches(const mnttab& m) const;
+#else
     bool matches(const mntent& m) const;
+#endif
     const char *dir() const		{ return mydir; }
     const char *fsname() const		{ return myfsname; }
     const Interests& interests()	{ return myinterests; }
--- fam-2.7.0/src/FileSystemTable.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/FileSystemTable.c++	2007-01-02 13:22:13.000000000 -0500
@@ -21,11 +21,13 @@
 //  Temple Place - Suite 330, Boston MA 02111-1307, USA.
 
 #include <stddef.h>
+#include <stdio.h>
 #include "FileSystemTable.h"
 
-#include <mntent.h>
+#include "fam-mntent.h"
 #include <stdlib.h>
 #include <string.h>
+#include <sys/param.h>
 
 #if HAVE_STATVFS
 #include <sys/statvfs.h>
@@ -106,7 +108,11 @@
 
     //  Read /etc/mtab.
     Cred::SuperUser.become_user();
+#if defined(HAVE_SYS_MNTTAB_H)
+    FILE *mtab = fopen(mtab_name, "r");
+#else
     FILE *mtab = setmntent(mtab_name, "r");
+#endif
     if(mtab == NULL)
     {
         Log::error("couldn't open %s for reading", mtab_name);
@@ -114,40 +120,86 @@
         return;
     }
     root = NULL;
+#if defined(HAVE_SYS_MNTTAB_H)
+    resetmnttab(mtab);
+    int ret = 0;
+    do
+#else
     for (mntent *mp; ((mp = getmntent(mtab)) != NULL); )
+#endif
     {
+#if defined(HAVE_SYS_MNTTAB_H)
+	struct mnttab ment, *mp;
+	mp = &ment;
+	ret = getmntent(mtab, mp);
+	FileSystem *fs = fs_by_name ? fs_by_name->find(mp->mnt_mountp) : NULL;
+#else
 	FileSystem *fs = fs_by_name ? fs_by_name->find(mp->mnt_dir) : NULL;
+#endif
 	if (fs && fs->matches(*mp))
 	{
 	    Log::debug("mtab: MATCH     \"%s\" on \"%s\" using type <%s>",
+#if defined(HAVE_SYS_MNTTAB_H)
+		       mp->mnt_special, mp->mnt_mountp, mp->mnt_fstype);
+
+	    new_fs_by_name->insert(mp->mnt_mountp, fs);
+	    if (dismounted_fses.find(mp->mnt_mountp))
+		dismounted_fses.remove(mp->mnt_mountp);
+#else
 		       mp->mnt_fsname, mp->mnt_dir, mp->mnt_type);
 
 	    new_fs_by_name->insert(mp->mnt_dir, fs);
 	    if (dismounted_fses.find(mp->mnt_dir))
 		dismounted_fses.remove(mp->mnt_dir);
+#endif
 	}
 	else
 	{
 
+#if defined(HAVE_SYS_MNTTAB_H)
+            if ((!strcmp(mp->mnt_fstype, MNTTYPE_NFS)
+#else
             if ((!strcmp(mp->mnt_type, MNTTYPE_NFS)
+#endif
 #if HAVE_MNTTYPE_NFS2
+#if defined(HAVE_SYS_MNTTAB_H)
+                || !strcmp(mp->mnt_fstype, MNTTYPE_NFS2)
+#else
                 || !strcmp(mp->mnt_type, MNTTYPE_NFS2)
 #endif
+#endif
 #if HAVE_MNTTYPE_NFS3
+#if defined(HAVE_SYS_MNTTAB_H)
+                || !strcmp(mp->mnt_fstype, MNTTYPE_NFS3)
+#else
                 || !strcmp(mp->mnt_type, MNTTYPE_NFS3)
 #endif
+#endif
 #if HAVE_MNTTYPE_CACHEFS
+#if defined(HAVE_SYS_MNTTAB_H)
+                || !strcmp(mp->mnt_fstype, MNTTYPE_CACHEFS)
+#else
                 || !strcmp(mp->mnt_type, MNTTYPE_CACHEFS)
 #endif
+#endif
+#if defined(HAVE_SYS_MNTTAB_H)
+                ) && strchr(mp->mnt_special, ':'))
+#else
                 ) && strchr(mp->mnt_fsname, ':'))
+#endif
             {
                 if(Log::get_level() == Log::DEBUG)
                 {
                     const char *mntopt = hasmntopt(mp, "dev");
                     if(mntopt == NULL) mntopt = "";
 		    Log::debug("mtab: new NFS   \"%s\" on \"%s\" %s using <%s>",
+#if defined(HAVE_SYS_MNTTAB_H)
+			       mp->mnt_special, mp->mnt_mountp, mntopt,
+                               mp->mnt_fstype);
+#else
 			       mp->mnt_fsname, mp->mnt_dir, mntopt,
                                mp->mnt_type);
+#endif
                 }
 
 		fs = new NFSFileSystem(*mp);
@@ -155,24 +207,45 @@
 	    else
 	    {
 		Log::debug("mtab: new local \"%s\" on \"%s\"",
+#if defined(HAVE_SYS_MNTTAB_H)
+			   mp->mnt_special, mp->mnt_mountp);
+#else
 			   mp->mnt_fsname, mp->mnt_dir);
+#endif
 
 		fs = new LocalFileSystem(*mp);
 	    }
+#if defined(HAVE_SYS_MNTTAB_H)
+	    new_fs_by_name->insert(mp->mnt_mountp, fs);
+#else
 	    new_fs_by_name->insert(mp->mnt_dir, fs);
+#endif
 	    if (fs_by_name)
 	    {
 		// Find parent filesystem.
 
+#if defined(HAVE_SYS_MNTTAB_H)
+		FileSystem *parent = longest_prefix(mp->mnt_mountp);
+#else
 		FileSystem *parent = longest_prefix(mp->mnt_dir);
+#endif
 		assert(parent);
 		mount_parents.insert(parent->dir(), parent);
 	    }
 	}
+#if defined(HAVE_SYS_MNTTAB_H)
+	if (!strcmp(mp->mnt_mountp, "/"))
+#else
 	if (!strcmp(mp->mnt_dir, "/"))
+#endif
 	    root = fs;
     }
+#if defined(HAVE_SYS_MNTTAB_H)
+    while (ret != -1);
+    fclose(mtab);
+#else
     endmntent(mtab);
+#endif
 
     if(root == NULL)
     {
@@ -255,7 +328,10 @@
     //  create_fs_by_name initializes our "root" member variable.
     if (!fs_by_name)
     {   create_fs_by_name();
+#if !defined(BSD)
+        /* there is no mtab "file" in BSD */
 	mtab_watcher = new InternalClient(mtab_name, mtab_event_handler, NULL);
+#endif
     }
 
     cr.become_user();
--- fam-2.7.0/src/IMon.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/IMon.c++	2007-01-02 13:22:13.000000000 -0500
@@ -25,6 +25,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <sys/param.h>
 
 #if HAVE_IMON
 #ifdef __sgi
@@ -32,15 +33,18 @@
 #else
 #include <linux/imon.h>
 #endif
+#else // HAVE_IMON
+#include "imon-compat.h"
 #endif
 
+#if HAVE_SYS_SYSMACROS_H
 #include <sys/sysmacros.h>
+#endif
 #include <unistd.h>
 
 #include "Interest.h"
 #include "Log.h"
 #include "Scheduler.h"
-#include "alloc.h"
 
 int		   IMon::imonfd = -2;
 IMon::EventHandler IMon::ehandler = NULL;
--- fam-2.7.0/src/IMonKQueue.c++	1969-12-31 19:00:00.000000000 -0500
+++ fam-2.7.0-patched/src/IMonKQueue.c++	2007-01-02 13:23:06.000000000 -0500
@@ -0,0 +1,453 @@
+//  $NetBSD: IMonKQueue.c++,v 1.3 2005/01/05 16:21:06 jmmv Exp $
+//
+//  Copyright (c) 2004, 2005 Julio M. Merino Vidal.
+//  
+//  This program is free software; you can redistribute it and/or modify it
+//  under the terms of version 2 of the GNU General Public License as
+//  published by the Free Software Foundation.
+//
+//  This program is distributed in the hope that it would be useful, but
+//  WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
+//  license provided herein, whether implied or otherwise, is limited to
+//  this program in accordance with the express provisions of the GNU
+//  General Public License.  Patent licenses, if any, provided herein do not
+//  apply to combinations of this program with other product or programs, or
+//  any other product whatsoever.  This program is distributed without any
+//  warranty that the program is delivered free of the rightful claim of any
+//  third person by way of infringement or the like.  See the GNU General
+//  Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with this program; if not, write the Free Software Foundation, Inc., 59
+//  Temple Place - Suite 330, Boston MA 02111-1307, USA.
+
+// ------------------------------------------------------------------------
+
+//  imon emulation through kqueue
+//  -----------------------------
+//
+//  The code in this file provides an imon-like interface to FAM using kqueue,
+//  the kernel event notification mechanism found in FreeBSD, NetBSD and
+//  OpenBSD.
+//
+//  The idea is the following: a thread, kqueue_monitor, simulates the kernel
+//  part of imon.  This thread can receive commands (ioctl(2)s) and produces
+//  notifications when there is something to notify.  The thread is constantly
+//  running in the background, calling kevent(2) to see if there are new
+//  events in the monitored files since the last call.
+//
+//  Communication with kqueue_monitor is accomplished by using two pipes.
+//  pipe_out is used by the monitor to provide notifications; i.e., it is the
+//  same as the read end of the regular /dev/imon device, and produces
+//  compatible messages.  On the other hand we have pipe_in, which is used
+//  to give commands to the monitor (express and revoke); we can't emulate
+//  ioctl(2)s from user space, so we have to go this route.
+//
+//  Why we use pipe_in to provide commands to the thread, instead of some
+//  mutexes?  If we used mutexes, we'd have to give kevent(2) a timeout, to
+//  let it "reload" the list of changes to be monitored in case it was
+//  externally modified.  By using a pipe, we can tell kqueue(2) to monitor
+//  it for us, and let kevent(2) immediately return when there is a command
+//  to process.
+//
+//  However, there is a little problem when using kqueue instead of imon or
+//  polling.  kqueue(2) works by monitoring open file descriptors, instead
+//  of inodes on the disk.  Therefore we must keep all files being monitored
+//  open, and the number of open files can quickly raise in some environments.
+//  This is why the code unlimits the number of open files in imon_open and
+//  sets a reasonable maximum based on kern.maxfiles (to avoid overflowing
+//  it quickly).  If we overflow this limit, the poller will enter the game
+//  (because we will return an error).
+//
+//  Known problem: if we receive *lots* of events quickly, famd may end up
+//  locked.  To reproduce, run the test program provided by fam against a
+//  local directory, say /tmp/foo, and do the following:
+//     cd /tmp/foo; for f in $(jot 1000); do touch $(jot 100); rm *; done
+//  You should receive some messages like:
+//     famd[21058]: kqueue can't revoke "75", dev = 0, ino = 1113421
+//  while the test is running (not a lot), and it will eventually lock up.
+//
+//  Having said all this, let's go to the code...
+
+// ------------------------------------------------------------------------
+
+#include "IMon.h"
+#include "Log.h"
+
+#include "config.h"
+#include "imon-compat.h"
+
+#include <sys/event.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <map>
+
+// ------------------------------------------------------------------------
+
+// devino is a structure that holds a device/inode pair.  It is used as an
+// indentifier of files managed by imon.
+struct devino {
+    dev_t di_dev;
+    ino_t di_ino;
+
+    bool operator<(const struct devino& di) const
+        { return (di_dev < di.di_dev) or
+                 (di_dev == di.di_dev and di_ino < di.di_ino); }
+};
+
+// imon_cmd simulates commands thrown to imon as ioctl(2)s (but remember
+// we use a pipe).
+struct imon_cmd {
+#define IMON_CMD_EXPRESS 0
+#define IMON_CMD_REVOKE 1
+    int ic_type;
+
+    // imon identifies files through a device/inode pair.
+    struct devino ic_di;
+
+    // A pipe that will be used to receive the result of the command
+    // (asynchronously).
+    int ic_stat[2];
+
+    // If this is an 'express' command, we need the descriptor to monitor.
+    int ic_fd;
+};
+
+// ------------------------------------------------------------------------
+
+static int max_changes;
+static int last_change;
+static int kqueue_fd;
+static int pipe_in[2], pipe_out[2];
+static pthread_t kevent_thread;
+static struct kevent *changes;
+
+typedef std::map<struct devino, int> DEVINOFD_MAP;
+static DEVINOFD_MAP devino_to_fd;
+typedef std::map<int, struct devino> FDDEVINO_MAP;
+static FDDEVINO_MAP fd_to_devino;
+
+// ------------------------------------------------------------------------
+
+static void *kqueue_monitor(void *data);
+static void process_command(void);
+
+// ------------------------------------------------------------------------
+
+int
+IMon::imon_open(void)
+{
+    // Get the kernel event queue.  We only need one during all the life
+    // of famd.
+    kqueue_fd = kqueue();
+    if (kqueue_fd == -1)
+        return -1;
+
+    // Create "emulation" pipes.
+    if (pipe(pipe_in) == -1) {
+        close(kqueue_fd);
+        return -1;
+    }
+    if (pipe(pipe_out) == -1) {
+        close(kqueue_fd);
+        close(pipe_in[0]); close(pipe_in[1]);
+        return -1;
+    }
+
+    // Get the maximum number of files we can open and use it to set a
+    // limit of the files we can monitor.
+    size_t len = sizeof(max_changes);
+    if (sysctlbyname("kern.maxfiles", &max_changes, &len, NULL, 0) == -1)
+        max_changes = 128;
+    else
+        max_changes /= 2;
+
+    // Unlimit maximum number of open files.  We don't go to RLIM_INFINITY
+    // to avoid possible open descriptor leaks produce a system DoS.  75%
+    // of the system limit seems a good number (we request more than the
+    // number calculated previously to leave room for temporary pipes).
+    // We need to be root to do this.
+    uid_t olduid = geteuid();
+    seteuid(0);
+    struct rlimit rlp;
+    rlp.rlim_cur = rlp.rlim_max = max_changes * 3 / 2;
+    if (setrlimit(RLIMIT_NOFILE, &rlp) == -1)
+        Log::error("can't unlimit number of open files");
+    seteuid(olduid);
+
+    changes = new struct kevent[max_changes];
+
+    // We must monitor pipe_in for any commands that may alter the actual
+    // set of files being monitored.
+    EV_SET(&changes[0], pipe_in[0], EVFILT_READ,
+           EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, 0);
+    last_change = 1;
+
+    // Create a thread that will run the kevent(2) function continuously.
+    if (pthread_create(&kevent_thread, NULL, kqueue_monitor, NULL) != 0) {
+        close(kqueue_fd);
+        close(pipe_in[0]); close(pipe_in[1]);
+        close(pipe_out[0]); close(pipe_out[1]);
+        return -1;
+    }
+
+    return pipe_out[0];
+}
+
+// ------------------------------------------------------------------------
+
+IMon::Status
+IMon::imon_express(const char *name, struct stat *status)
+{
+    // Get file information.
+    struct stat sb;
+    if (status == NULL)
+        status = &sb;
+    if (lstat(name, status) == -1)
+        return BAD;
+
+    // Open the file to be monitored; kqueue only works with open descriptors
+    // so we have to keep this descriptor during the life of this 'interest'.
+    int fd = open(name, O_RDONLY);
+    if (fd == -1)
+        return BAD;
+
+    // Construct a command to 'express' interest in a file.  This will be
+    // handled by the kqueue_monitor thread as soon as possible.
+    struct imon_cmd cmd;
+    cmd.ic_type = IMON_CMD_EXPRESS;
+    cmd.ic_di.di_dev = status->st_dev;
+    cmd.ic_di.di_ino = status->st_ino;
+    cmd.ic_fd = fd;
+    if (pipe(cmd.ic_stat) == -1) {
+        close(fd);
+        return BAD;
+    }
+    write(pipe_in[1], &cmd, sizeof(struct imon_cmd));
+
+    // Wait for a result form the previous operation.
+    bool result;
+    read(cmd.ic_stat[0], &result, sizeof(bool));
+    close(cmd.ic_stat[0]); close(cmd.ic_stat[1]);
+    if (!result) {
+        close(fd);
+        Log::error("kqueue can't monitor more than %d files", max_changes);
+        return BAD;
+    }
+
+    Log::debug("told kqueue to monitor \"%s\", descriptor = %d, dev = %d, "
+               "ino = %d", name, cmd.ic_fd, cmd.ic_di.di_dev,
+               cmd.ic_di.di_ino);
+
+    return OK;
+}
+
+// ------------------------------------------------------------------------
+
+IMon::Status
+IMon::imon_revoke(const char *name, dev_t dev, ino_t ino)
+{
+    // Construct a command to 'revoke' interest from a file.  This will be
+    // handled by the kqueue_monitor thread as soon as possible.
+    struct imon_cmd cmd;
+    cmd.ic_type = IMON_CMD_REVOKE;
+    cmd.ic_di.di_dev = dev;
+    cmd.ic_di.di_ino = ino;
+    if (pipe(cmd.ic_stat) == -1)
+        return BAD;
+    write(pipe_in[1], &cmd, sizeof(struct imon_cmd));
+
+    // Wait for a result form the previous operation.
+    bool result;
+    read(cmd.ic_stat[0], &result, sizeof(bool));
+    close(cmd.ic_stat[0]); close(cmd.ic_stat[1]);
+    if (!result) {
+        Log::error("kqueue can't revoke \"%s\", dev = %d, ino = %d", name,
+                   cmd.ic_di.di_dev, cmd.ic_di.di_ino);
+        return BAD;
+    }
+
+    Log::debug("told kqueue to forget \"%s\", dev = %d, ino = %d", name,
+               cmd.ic_di.di_dev, cmd.ic_di.di_ino);
+
+    return OK;
+}
+
+// ------------------------------------------------------------------------
+
+static void *
+kqueue_monitor(void *data)
+{
+    struct kevent event;
+
+    for (;;) {
+        int nev = kevent(kqueue_fd, changes, last_change, &event, 1, NULL);
+        if (nev == -1)
+            Log::perror("kevent");
+        else if (nev > 0) {
+            assert(nev == 1);
+
+            if (event.flags & EV_ERROR) {
+                int fd = event.ident;
+
+                FDDEVINO_MAP::const_iterator iter = fd_to_devino.find(fd);
+                assert(iter != fd_to_devino.end());
+                struct devino di = iter->second;
+
+                Log::error("kqueue returned error for fd = %d, dev = %d, "
+                           "ino = %d", fd, di.di_dev, di.di_ino);
+
+                // Remove offending entry from the mappings.
+                assert(devino_to_fd.find(di) != devino_to_fd.end());
+                devino_to_fd.erase(di);
+                assert(devino_to_fd.find(di) == devino_to_fd.end());
+                assert(fd_to_devino.find(fd) != fd_to_devino.end());
+                fd_to_devino.erase(fd);
+                assert(fd_to_devino.find(fd) == fd_to_devino.end());
+
+                // Remove the entry associated to the descriptor from the list
+                // of changes monitored by kqueue.
+                int i;
+                for (i = 1; i < last_change; i++)
+                    if (changes[i].ident == fd)
+                        break;
+                for (int j = i; j < last_change - 1; j++)
+                    changes[j] = changes[j + 1];
+                last_change--;
+
+                close(fd);
+
+                continue;
+            }
+
+            if (event.ident == pipe_in[0]) {
+                // We have got a control command, so process it.
+                process_command();
+            } else {
+                // One of the descriptors we are monitoring has got activity.
+                FDDEVINO_MAP::const_iterator iter =
+                    fd_to_devino.find(event.ident);
+                if (iter != fd_to_devino.end()) {
+                    qelem_t elem;
+
+                    // Set device/inode identifier on imon element.
+                    const struct devino &di = (*iter).second;
+                    elem.qe_dev = di.di_dev;
+                    elem.qe_inode = di.di_ino;
+
+                    // Convert the modification flags reported by kqueue to
+                    // flags understood by imon.
+                    elem.qe_what = 0;
+                    if (event.fflags & NOTE_DELETE)
+                        elem.qe_what |= IMON_DELETE;
+                    if (event.fflags & NOTE_RENAME)
+                        elem.qe_what |= IMON_RENAME;
+                    if (event.fflags & NOTE_ATTRIB or event.fflags & NOTE_LINK)
+                        elem.qe_what |= IMON_ATTRIBUTE;
+                    if (event.fflags & NOTE_WRITE or event.fflags & NOTE_EXTEND)
+                        elem.qe_what |= IMON_CONTENT;
+
+                    // Deliver the element.
+                    write(pipe_out[1], &elem, sizeof(qelem_t));
+                } else
+                    Log::error("got an event from an unhandled device/inode "
+                               "pair");
+            }
+        }
+    }
+}
+
+// ------------------------------------------------------------------------
+
+static void
+process_command(void)
+{
+    bool result = false;
+    struct imon_cmd cmd;
+
+    // Read the command from the control pipe.
+    read(pipe_in[0], &cmd, sizeof(struct imon_cmd));
+    if (cmd.ic_type == IMON_CMD_EXPRESS) {
+        Log::debug("process_command: express, dev = %d, ino = %d",
+                   cmd.ic_di.di_dev, cmd.ic_di.di_ino);
+        if (devino_to_fd.find(cmd.ic_di) != devino_to_fd.end()) {
+            // The file is already being monitored.
+            close(cmd.ic_fd);
+            result = true;
+        } else if (fd_to_devino.find(cmd.ic_fd) != fd_to_devino.end()) {
+            // We can't receive a new interest of a descriptor that is
+            // already being monitored.  If this happens, there is an
+            // inconsistency in the data somewhere.
+            assert(false);
+        } else if (last_change < max_changes) {
+            // Add the new descriptor to the list of changes to monitor.
+            // We watch for any change that happens on it.
+            EV_SET(&changes[last_change], cmd.ic_fd, EVFILT_VNODE,
+                   EV_ADD | EV_ENABLE | EV_ONESHOT,
+                   NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
+                   NOTE_LINK | NOTE_RENAME | NOTE_REVOKE,
+                   0, 0);
+            last_change++;
+
+            // Map the device/inode pair to the file descriptor associated
+            // to it and viceversa.  We will need this information during
+            // 'revoke' and when we receive events.  We use two different
+            // maps to speed up searches in both directions later.
+            assert(devino_to_fd.find(cmd.ic_di) == devino_to_fd.end());
+            devino_to_fd.insert
+                (DEVINOFD_MAP::value_type(cmd.ic_di, cmd.ic_fd));
+            assert(devino_to_fd.find(cmd.ic_di) != devino_to_fd.end());
+            assert(fd_to_devino.find(cmd.ic_fd) == fd_to_devino.end());
+            fd_to_devino.insert
+                (FDDEVINO_MAP::value_type(cmd.ic_fd, cmd.ic_di));
+            assert(fd_to_devino.find(cmd.ic_fd) != fd_to_devino.end());
+
+            result = true;
+        }
+    } else if (cmd.ic_type == IMON_CMD_REVOKE) {
+        Log::debug("process_command: revoke, dev = %d, ino = %d",
+                   cmd.ic_di.di_dev, cmd.ic_di.di_ino);
+        DEVINOFD_MAP::const_iterator iter = devino_to_fd.find(cmd.ic_di);
+        if (iter != devino_to_fd.end()) {
+            // Get the descriptor associated to the given device/inode pair
+            // and remove the mapping from the required structure.
+            int fd = (*iter).second;
+            assert(devino_to_fd.find(cmd.ic_di) != devino_to_fd.end());
+            devino_to_fd.erase(cmd.ic_di);
+            assert(devino_to_fd.find(cmd.ic_di) == devino_to_fd.end());
+            assert(fd_to_devino.find(fd) != fd_to_devino.end());
+            fd_to_devino.erase(fd);
+            assert(fd_to_devino.find(fd) == fd_to_devino.end());
+
+            // Remove the entry associated to the descriptor from the list
+            // of changes monitored by kqueue.
+            int i;
+            for (i = 1; i < last_change; i++)
+                if (changes[i].ident == fd)
+                    break;
+            for (int j = i; j < last_change - 1; j++)
+                changes[j] = changes[j + 1];
+            last_change--;
+
+            close(fd);
+
+            result = true;
+        }
+    } else {
+        // Huh?  Unknown command received.
+        assert(false);
+    }
+
+    // Deliver the result of the operation.
+    write(cmd.ic_stat[1], &result, sizeof(bool));
+}
--- fam-2.7.0/src/Interest.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/Interest.c++	2007-01-02 13:22:13.000000000 -0500
@@ -23,7 +23,9 @@
 #include "Interest.h"
 
 #include <sys/param.h>
+#if HAVE_SYS_SYSMACROS_H
 #include <sys/sysmacros.h>
+#endif
 
 #include <errno.h>
 #include <string.h>
@@ -46,7 +48,7 @@
 #include "Pollster.h"
 #include "timeval.h"
 
-Interest *Interest::hashtable[];
+Interest *Interest::hashtable[HASHSIZE];
 IMon      Interest::imon(imon_handler);
 bool      Interest::xtab_verification = true;
 
--- fam-2.7.0/src/InternalClient.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/InternalClient.c++	2007-01-02 13:22:13.000000000 -0500
@@ -35,8 +35,8 @@
 {
     assert(filename);
     assert(h);
-    assert(filename[0] == '/');
     Log::debug("%s watching %s", name(), filename);
+    assert(filename[0] == '/');
     interest = new File(filename, this, Request(0), Cred::SuperUser);
 }
 
--- fam-2.7.0/src/Listener.c++	2003-01-19 19:37:29.000000000 -0500
+++ fam-2.7.0-patched/src/Listener.c++	2007-01-02 13:22:13.000000000 -0500
@@ -22,6 +22,8 @@
 
 #include "Listener.h"
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <assert.h>
 #include <fcntl.h>
 #include <sys/types.h>
@@ -32,6 +34,7 @@
 #include <rpc/clnt.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/un.h>
 #include <unistd.h>
@@ -205,11 +208,11 @@
 #ifdef HAVE_UNSETENV
     unsetenv("TMPDIR");
 #else
-    putenv("TMPDIR=");
+    putenv("TMPDIR=/tmp");
 #endif
 
     char *tmpfile = tempnam("/tmp", ".fam");
-#ifdef HAVE_SOCKADDR_SUN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
     sockaddr_un sun = { sizeof(sockaddr_un), AF_UNIX, "" };
 #else
     sockaddr_un sun = { AF_UNIX, "" };
@@ -283,7 +286,7 @@
 
     // Get the new socket.
 
-#ifdef HAVE_SOCKADDR_SUN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
     struct sockaddr_un sun = { sizeof(sockaddr_un), AF_UNIX, "" };
 #else
     struct sockaddr_un sun = { AF_UNIX, "" };
@@ -349,7 +352,7 @@
 void
 Listener::dirty_ugly_hack()
 {
-#ifdef HAVE_SOCKADDR_SUN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
     static sockaddr_un sun = { sizeof (sockaddr_un), AF_UNIX, "/tmp/.fam_socket" };
 #else
     static sockaddr_un sun = { AF_UNIX, "/tmp/.fam_socket" };
--- fam-2.7.0/src/LocalFileSystem.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/LocalFileSystem.c++	2007-01-02 13:22:14.000000000 -0500
@@ -27,7 +27,11 @@
 #include "Log.h"
 #include "Pollster.h"
 
+#if defined(HAVE_SYS_MNTTAB_H)
+LocalFileSystem::LocalFileSystem(const mnttab& mnt)
+#else
 LocalFileSystem::LocalFileSystem(const mntent& mnt)
+#endif
     : FileSystem(mnt)
 { }
 
--- fam-2.7.0/src/LocalFileSystem.h	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/LocalFileSystem.h	2007-01-02 13:22:14.000000000 -0500
@@ -38,7 +38,11 @@
 
 public:
 
+#if defined(HAVE_SYS_MNTTAB_H)
+    LocalFileSystem(const mnttab&);
+#else
     LocalFileSystem(const mntent&);
+#endif
 
     virtual bool dir_entries_scanned() const;
     virtual int get_attr_cache_timeout() const;
--- fam-2.7.0/src/Log.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/Log.c++	2007-01-02 13:22:14.000000000 -0500
@@ -28,9 +28,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <syslog.h>
+#include <sys/time.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
 #ifdef HAVE_AUDIT
--- fam-2.7.0/src/NFSFileSystem.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/NFSFileSystem.c++	2007-01-02 13:22:13.000000000 -0500
@@ -24,7 +24,7 @@
 #include "NFSFileSystem.h"
 
 #include <assert.h>
-#include <mntent.h>
+#include "fam-mntent.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -41,12 +41,20 @@
 #define ACREGMIN 3
 #endif
 
+#if defined(HAVE_SYS_MNTTAB_H)
+NFSFileSystem::NFSFileSystem(const mnttab& mnt)
+#else
 NFSFileSystem::NFSFileSystem(const mntent& mnt)
+#endif
     : FileSystem(mnt)
 {
     //  Extract the host name from the fs name.
 
+#if defined(HAVE_SYS_MNTTAB_H)
+    const char *fsname = mnt.mnt_special;
+#else
     const char *fsname = mnt.mnt_fsname;
+#endif
     const char *colon = strchr(fsname, ':');
     if(colon == NULL)
     {
@@ -55,12 +63,12 @@
         assert(colon);
         colon = fsname;
     }
-    char hostname[NAME_MAX + 1];
+    char hostname[MAXPATHLEN + 1];
     int hostnamelen = colon - fsname;
-    if(hostnamelen > NAME_MAX)
+    if(hostnamelen > MAXPATHLEN)
     {
-        assert(hostnamelen <= NAME_MAX);
-        hostnamelen = NAME_MAX;
+        assert(hostnamelen <= MAXPATHLEN);
+        hostnamelen = MAXPATHLEN;
     }
     strncpy(hostname, fsname, hostnamelen);
     hostname[hostnamelen] = '\0';
@@ -84,7 +92,11 @@
     // acregmin, acregmax, actimeo, and noac options in the mount
     // options.  Otherwise, use defaults.
 
+#if defined(HAVE_SYS_MNTTAB_H)
+    const char * opt = mnt.mnt_mntopts;
+#else
     const char * opt = mnt.mnt_opts;
+#endif
 
     bool f_noac = false;
     bool f_actimeo = false;
@@ -102,20 +114,20 @@
     if (strstr(opt, "noac")) {
         f_noac = true;
     }
-    if ((p = strstr(opt, "actimeo"))) 
+    if ((p = strstr((char *)opt, "actimeo"))) 
     {
         if (sscanf(p, "actimeo=%i", &actimeo) == 1) {
             f_actimeo = true;
         }
     }
     
-    if ((p = strstr(opt, "acregmin"))) {
+    if ((p = strstr((char *)opt, "acregmin"))) {
         if (sscanf(p, "acregmin=%i", &acregmin) == 1) {
             f_acregmin = true;
         }
     }
     
-    if ((p = strstr(opt, "acregmax"))) {
+    if ((p = strstr((char *)opt, "acregmax"))) {
         if (sscanf(p, "acregmax=%i", &acregmax) == 1) {
             f_acregmax = true;
         }
--- fam-2.7.0/src/NFSFileSystem.h	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/NFSFileSystem.h	2007-01-02 13:22:14.000000000 -0500
@@ -39,7 +39,11 @@
 
 public:
 
+#if defined(HAVE_SYS_MNTTAB_H)
+    NFSFileSystem(const mnttab&);
+#else
     NFSFileSystem(const mntent&);
+#endif
     ~NFSFileSystem();
 
     virtual bool dir_entries_scanned() const;
--- fam-2.7.0/src/NetConnection.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/NetConnection.c++	2007-01-02 13:22:14.000000000 -0500
@@ -21,6 +21,7 @@
 //  Temple Place - Suite 330, Boston MA 02111-1307, USA.
 
 #include "NetConnection.h"
+#include "config.h"
 
 #include <assert.h>
 #include <errno.h>
@@ -29,6 +30,9 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
 #include <sys/socket.h>
 #include <unistd.h>
 #include <netinet/in.h>
--- fam-2.7.0/src/NetConnection.h	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/NetConnection.h	2007-01-02 13:22:14.000000000 -0500
@@ -68,6 +68,8 @@
     void ready_for_input(bool);
     int get_fd() const { return fd; }
 
+    enum { MAXMSGSIZE = PATH_MAX + 40 };
+
 protected:
 
     virtual bool input_msg(const char *data, unsigned nbytes) = 0;
@@ -75,7 +77,6 @@
 
 private:
 
-    enum { MAXMSGSIZE = PATH_MAX + 40 };
     typedef u_int32_t Length;
     typedef struct msgList_s {
         char msg[MAXMSGSIZE+5];  //  + 4 for 32-bit length, + 1 for overflow
--- fam-2.7.0/src/RPC_TCP_Connector.c++	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/RPC_TCP_Connector.c++	2007-01-02 13:22:14.000000000 -0500
@@ -21,11 +21,23 @@
 //  Temple Place - Suite 330, Boston MA 02111-1307, USA.
 
 #include "RPC_TCP_Connector.h"
+#include "config.h"
+
+#define PORTMAP
 
 #include <errno.h>
+#ifdef __SUNPRO_CC
+extern "C" {
+#endif
 #include <rpc/rpc.h>
 #include <rpc/pmap_prot.h>
+#ifdef __SUNPRO_CC
+}
+#endif
 #include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
 #include <sys/socket.h>
 #include <unistd.h>
 #include <string.h>
--- fam-2.7.0/src/Scheduler.h	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/Scheduler.h	2007-01-02 13:22:14.000000000 -0500
@@ -88,8 +88,6 @@
     static void loop()			{ running = true;
 					  while (running) select(); }
 
-private:
-
     //  Per-filedescriptor info is the set of three handlers and their
     //  closures.
 
--- fam-2.7.0/src/ServerHost.h	2003-01-18 09:18:12.000000000 -0500
+++ fam-2.7.0-patched/src/ServerHost.h	2007-01-02 13:22:14.000000000 -0500
@@ -24,6 +24,7 @@
 #define ServerHost_included
 
 #include <limits.h>
+#include <stdio.h>
 #include "Boolean.h"
 #include "ClientInterest.h"
 #include "RequestMap.h"
@@ -101,7 +102,7 @@
     private:
 
 	Request myrequest;
-	char mypath[NAME_MAX];
+	char mypath[MAXPATHLEN];
 
     };
 
--- fam-2.7.0/src/fam-mntent.h	1969-12-31 19:00:00.000000000 -0500
+++ fam-2.7.0-patched/src/fam-mntent.h	2007-01-02 13:22:14.000000000 -0500
@@ -0,0 +1,62 @@
+/*
+ *  mntent
+ *  fam-mntent.h - compatability header for BSD
+ *
+ *  Copyright (c) 2001 David Rufino <daverufino@btinternet.com>
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(HAVE_MNTENT_H)
+#include <mntent.h>
+#elif defined(HAVE_SYS_MNTTAB_H)
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#define MOUNTED MNTTAB
+#else
+#ifndef _MNTENT_H
+#define _MNTENT_H
+#include <stdio.h>
+
+#define MOUNTED "dummy"
+
+#define MNTTYPE_NFS "nfs"
+
+struct mntent {
+	char *mnt_fsname;
+	char *mnt_dir;
+	char *mnt_type;
+	char *mnt_opts;
+	int mnt_freq;
+	int mnt_passno;
+};
+
+#define setmntent(x,y) ((FILE *)0x1)
+struct mntent *getmntent __P ((FILE *fp));
+char *hasmntopt __P ((const struct mntent *mnt, const char *option));
+#define endmntent(x) ((int)1)
+
+#endif /* _MNTENT_H */
+#endif /* HAVE_MNTENT_H */
--- fam-2.7.0/src/imon-compat.h	1969-12-31 19:00:00.000000000 -0500
+++ fam-2.7.0-patched/src/imon-compat.h	2007-01-02 13:23:12.000000000 -0500
@@ -0,0 +1,53 @@
+//  $NetBSD: imon-compat.h,v 1.1 2004/10/17 19:20:53 jmmv Exp $
+//
+//  Copyright (c) 2004 Julio M. Merino Vidal.
+//  
+//  This program is free software; you can redistribute it and/or modify it
+//  under the terms of version 2 of the GNU General Public License as
+//  published by the Free Software Foundation.
+//
+//  This program is distributed in the hope that it would be useful, but
+//  WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
+//  license provided herein, whether implied or otherwise, is limited to
+//  this program in accordance with the express provisions of the GNU
+//  General Public License.  Patent licenses, if any, provided herein do not
+//  apply to combinations of this program with other product or programs, or
+//  any other product whatsoever.  This program is distributed without any
+//  warranty that the program is delivered free of the rightful claim of any
+//  third person by way of infringement or the like.  See the GNU General
+//  Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License along
+//  with this program; if not, write the Free Software Foundation, Inc., 59
+//  Temple Place - Suite 330, Boston MA 02111-1307, USA.
+
+#if !defined(IMON_COMPAT_H)
+#define IMON_COMPAT_H
+
+#if defined(HAVE_IMON)
+#  error "cannot include imon-compat.h if imon is really present"
+#endif
+
+#if defined(HAVE_KQUEUE)
+#define HAVE_IMON 1
+
+typedef int intmask_t;
+
+typedef struct {
+    dev_t qe_dev;
+    ino_t qe_inode;
+    intmask_t qe_what;
+} qelem_t;
+
+#define IMON_CONTENT    (1 << 0)
+#define IMON_ATTRIBUTE  (1 << 1)
+#define IMON_DELETE     (1 << 2)
+#define IMON_EXEC       (1 << 3)
+#define IMON_EXIT       (1 << 4)
+#define IMON_RENAME     (1 << 5)
+#define IMON_OVER       0xff
+
+#endif // defined(HAVE_KQUEUE)
+
+#endif // !defined(IMON_COMPAT_H)
--- fam-2.7.0/src/mntent_compat.c++	1969-12-31 19:00:00.000000000 -0500
+++ fam-2.7.0-patched/src/mntent_compat.c++	2007-01-02 13:22:14.000000000 -0500
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1980, 1989, 1993, 1994
+ *      The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2001
+ *      David Rufino <daverufino@btinternet.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* most of this was ripped from the mount(3) source */
+
+#include "config.h"
+#include "fam-mntent.h"
+#if !defined(HAVE_MNTENT_H) && !defined(HAVE_SYS_MNTTAB_H)
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#if defined(HAVE_SYS_STATVFS_H) && !defined(__APPLE__) && !defined(__DragonFly__) && !defined(__FreeBSD__)
+# include <sys/statvfs.h>
+#endif
+
+static int pos = -1;
+static int mntsize = -1;
+static struct mntent _mntent;
+
+char *
+hasmntopt (const struct mntent *mnt, const char *option)
+{
+        int found;
+        char *opt, *optbuf;
+
+        optbuf = strdup(mnt->mnt_opts);
+        found = 0;
+        for (opt = optbuf; (opt = strtok(opt, " ")) != NULL; opt = NULL) {
+                if (!strcasecmp(opt, option)) {
+			opt = opt - optbuf + mnt->mnt_opts;
+			free (optbuf);
+			return (opt);
+		}
+        }
+	free (optbuf);
+        return (NULL);
+}
+
+static char *
+catopt (char *s0, const char *s1)
+{
+        size_t i;
+        char *cp;
+
+        if (s1 == NULL || *s1 == '\0')
+                return s0;
+        if (s0 && *s0) {
+                i = strlen(s0) + strlen(s1) + 1 + 1;
+                if ((cp = (char *)malloc(i)) == NULL)
+			return (NULL);
+                (void)snprintf(cp, i, "%s %s", s0, s1);
+        } else
+                cp = strdup(s1);
+
+        if (s0)
+                free(s0);
+        return (cp);
+}
+
+
+static char *
+flags2opts (int flags)
+{
+        char *res;
+        res = NULL;
+        res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw");
+        if (flags & MNT_SYNCHRONOUS)    res = catopt(res, "sync");
+        if (flags & MNT_NOEXEC)         res = catopt(res, "noexec");
+        if (flags & MNT_NOSUID)         res = catopt(res, "nosuid");
+        if (flags & MNT_NODEV)          res = catopt(res, "nodev");
+        if (flags & MNT_UNION)          res = catopt(res, "union");
+        if (flags & MNT_ASYNC)          res = catopt(res, "async");
+#ifdef MNT_NOATIME
+        if (flags & MNT_NOATIME)        res = catopt(res, "noatime");
+#endif
+#ifdef MNT_NOCLUSTERR
+        if (flags & MNT_NOCLUSTERR)     res = catopt(res, "noclusterr");
+#endif
+#ifdef MNT_NOCLUSTERW
+        if (flags & MNT_NOCLUSTERW)     res = catopt(res, "noclusterw");
+#endif
+#ifdef MNT_NOSYMFOLLOW
+        if (flags & MNT_NOSYMFOLLOW)    res = catopt(res, "nosymfollow");
+#endif
+#ifdef MNT_SUIDDIR
+        if (flags & MNT_SUIDDIR)        res = catopt(res, "suiddir");
+#endif
+#ifdef MNT_NOCOREDUMP
+        if (flags & MNT_NOCOREDUMP)	res = catopt(res, "nocoredump");
+#endif
+#ifdef MNT_IGNORE
+        if (flags & MNT_IGNORE)		res = catopt(res, "hidden");
+#endif
+#ifdef MNT_SYMPERM
+        if (flags & MNT_SYMPERM)	res = catopt(res, "symperm");
+#endif
+#ifdef MNT_NODEVMTIME
+        if (flags & MNT_NODEVMTIME)	res = catopt(res, "nodevmtime");
+#endif
+#ifdef MNT_SOFTDEP
+        if (flags & MNT_SOFTDEP)	res = catopt(res, "softdep");
+#endif
+
+        return res;
+}
+
+static struct mntent *
+#if defined(HAVE_SYS_STATVFS_H) && !defined(__APPLE__) && !defined(__DragonFly__) && !defined(__FreeBSD__)
+statfs_to_mntent (struct statvfs *mntbuf)
+#else
+statfs_to_mntent (struct statfs *mntbuf)
+#endif
+{
+	static char opts_buf[40], *tmp;
+	
+	_mntent.mnt_fsname = mntbuf->f_mntfromname;
+	_mntent.mnt_dir = mntbuf->f_mntonname;
+	_mntent.mnt_type = mntbuf->f_fstypename;
+#if defined(HAVE_SYS_STATVFS_H) && !defined(__APPLE__) && !defined(__DragonFly__) && !defined(__FreeBSD__)
+	tmp = flags2opts (mntbuf->f_flag);
+#else
+	tmp = flags2opts (mntbuf->f_flags);
+#endif
+	if (tmp) {
+		opts_buf[sizeof(opts_buf)-1] = '\0';
+		strncpy (opts_buf, tmp, sizeof(opts_buf)-1);
+		free (tmp);
+	} else {
+		*opts_buf = '\0';
+	}
+	_mntent.mnt_opts = opts_buf;	
+	_mntent.mnt_freq = _mntent.mnt_passno = 0;
+	return (&_mntent);
+}
+
+struct mntent *
+getmntent (FILE *fp)
+{
+#if defined(HAVE_SYS_STATVFS_H) && !defined(__APPLE__) && !defined(__DragonFly__) && !defined(__FreeBSD__)
+	static struct statvfs *mntbuf;
+#else
+	static struct statfs *mntbuf;
+#endif
+
+	if (pos == -1 || mntsize == -1)
+		mntsize = getmntinfo (&mntbuf, MNT_NOWAIT);
+
+	++pos;
+	if (pos == mntsize) {
+		pos = mntsize = -1;
+		return (NULL);
+	}
+
+	return (statfs_to_mntent (&mntbuf[pos]));
+}
+
+#endif /* HAVE_MNTENT_H */
--- fam-2.7.0/src/Makefile.am	2003-01-19 07:00:17.000000000 -0500
+++ fam-2.7.0-patched/src/Makefile.am	2007-01-02 14:19:24.000000000 -0500
@@ -71,7 +71,8 @@
   main.c++ \
   timeval.c++ \
   timeval.h \
-  @MONITOR_FUNCS@.c++
+  IMonKQueue.c++ \
+  mntent_compat.c++
 
 EXTRA_famd_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++
 
