View | Details | Raw Unified
Collapse All | Expand All

(-) fam-2.7.0/src/Monitor.h (-31 / +794 lines)
Line 0    Link Here 
//  Copyright (C) 2001 Red Hat, Inc.  All Rights Reserved.
//  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
//  
//  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.
#define _GNU_SOURCE  
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <libgen.h>
#include "DNotify.h"
#include "Interest.h"
#include "Log.h"
#include "Scheduler.h"
#include <memory>
int DNotify::pipe_write_fd = -2;
int DNotify::pipe_read_fd = -2;
volatile sig_atomic_t DNotify::queue_overflowed = 0;
volatile sig_atomic_t DNotify::queue_changed = 0;
int DNotify::change_queue[QUEUESIZE];
volatile int DNotify::queue_head = 0; // Only modified by read handler
volatile int DNotify::queue_tail = 0; // Only modified by signal handler
DNotify::EventHandler DNotify::ehandler;
DNotify::DirWatch *DNotify::dir_hash[DIR_HASHSIZE];
DNotify::FileWatch *DNotify::file_hash[FILE_HASHSIZE];
struct DNotify::FileWatch
{
    DirWatch *dir_watch;
    dev_t file_dev;
    ino_t file_ino;
    FileWatch *next; // The DirWatch.watches list
    FileWatch *hash_link;
};
struct DNotify::DirWatch
{
    int fd;
    dev_t dir_dev;
    ino_t dir_ino;
    
    DirWatch *hash_link;
    FileWatch *watches;
};
struct DNotify::ChangeEventData
{
    dev_t file_dev;
    ino_t file_ino;
};    
DNotify::DNotify(EventHandler h)
{
    assert(ehandler == NULL);
    ehandler = h;
}
DNotify::~DNotify()
{
    if (pipe_read_fd >= 0)
    {
	//  Tell the scheduler.
	(void) Scheduler::remove_read_handler(pipe_read_fd);
	//  Close the pipe.
	if (close(pipe_read_fd) < 0)
	    Log::perror("can't pipe read end");
	else
	    Log::debug("closed pipe read end");
	
	if (close(pipe_write_fd) < 0)
	    Log::perror("can't pipe write end");
	else
	    Log::debug("closed pipe write end");
	pipe_read_fd = -1;
    }
    ehandler = NULL;
}
void
DNotify::overflow_signal_handler(int sig, siginfo_t *si, void *data)
{
  char c = 'x';
  {
    char *str = "*************** overflow sigqueue ***********************\n";
    write (STDERR_FILENO, str, strlen(str));
  }
  if (!queue_overflowed)
  {
      queue_overflowed = 1;
      // Trigger the read handler
      write(pipe_write_fd, &c, 1);
  }
}
void
DNotify::signal_handler(int sig, siginfo_t *si, void *data)
{
  int left;
  char c = 'x';
  if (queue_head <= queue_tail)
    left = (QUEUESIZE + queue_head) - queue_tail;
  else 
    left = queue_head - queue_tail;
  
  // Must leave at least one item unused to see difference
  // Betweeen empty and full
  if (left <= 1)
  {
      queue_overflowed = 1;
      {
	char *str = "*************** overflow famqueue ****************\n";
	write (STDERR_FILENO, str, strlen(str));
      }
  }
  else
  {
      change_queue[queue_tail] = si->si_fd;
      queue_tail = (queue_tail + 1) % QUEUESIZE;
  }
  
  if (!queue_changed)
  {
      queue_changed = 1;
      // Trigger the read handler
      write(pipe_write_fd, &c, 1);
  }
}
bool
DNotify::is_active()
{
    if (pipe_read_fd == -2)
    {
        int filedes[2];
	int res;
	
	res = pipe (filedes);
	if (res >= 0)
	{   Log::debug("opened pipe");
   	    pipe_read_fd = filedes[0];
   	    pipe_write_fd = filedes[1];
	    // Setup signal handler:
	    struct sigaction act;
	    
	    act.sa_sigaction = signal_handler;
	    sigemptyset(&act.sa_mask);
	    act.sa_flags = SA_SIGINFO;
	    sigaction(SIGRTMIN, &act, NULL);
	    // When the RT queue overflows we get a SIGIO
	    act.sa_sigaction = overflow_signal_handler;
	    sigemptyset(&act.sa_mask);
	    sigaction(SIGIO, &act, NULL);
	    (void) Scheduler::install_read_handler(pipe_read_fd, read_handler, NULL);
	}
    }
    return pipe_read_fd >= 0;
}
DNotify::DirWatch *
DNotify::lookup_dirwatch (int fd)
{
  DirWatch **p;
  DirWatch *w;
  p = dir_hashchain (fd);
  while (*p)
    {
      w = *p;
      if (w->fd == fd)
	return w;
      p = &w->hash_link;
    }
  
  return *p;
}
// This colud be made faster by using another hash table.
// But it's not that bad, since it is only used by express/revoke
DNotify::DirWatch *
DNotify::lookup_dirwatch (dev_t dir_dev, ino_t dir_ino)
{
  DirWatch *p;
  int i;
  for (i=0;i<DIR_HASHSIZE;i++)
    {
      p = dir_hash[i];
      
      while (p)
	{
	  if (p->dir_dev == dir_dev && p->dir_ino == dir_ino)
	    return p;
	  
	  p = p->hash_link;
	}
    }
  
  return NULL;
}
DNotify::FileWatch *
DNotify::lookup_filewatch (dev_t dev, ino_t ino)
{
  FileWatch **p;
  FileWatch *w;
  p = file_hashchain (dev, ino);
  while (*p)
    {
      w = *p;
      if (w->file_dev == dev && w->file_ino == ino)
	return w;
      p = &w->hash_link;
    }
  
  return *p;
}
// Make sure w is not already in the hash table before calling
// this function.
void
DNotify::hash_dirwatch(DirWatch *w)
{
  DirWatch **p;
  p = dir_hashchain (w->fd);
  w->hash_link = *p;
  *p = w;
}
// Make sure w is not already in the hash table before calling
// this function.
void
DNotify::hash_filewatch(FileWatch *w)
{
  FileWatch **p;
  p = file_hashchain (w->file_dev, w->file_ino);
  w->hash_link = *p;
  *p = w;
}
void
DNotify::unhash_dirwatch(DirWatch *w)
{
  DirWatch **p;
  
  p = dir_hashchain (w->fd);
  
  while (*p)
    {
      if (*p == w)
	{
	  *p = w->hash_link;
	  break;
	}
      p = &(*p)->hash_link;
    }
  w->hash_link = NULL;
}
void
DNotify::unhash_filewatch(FileWatch *w)
{
  FileWatch **p;
  
  p = file_hashchain (w->file_dev, w->file_ino);
  
  while (*p)
    {
      if (*p == w)
	{
	  *p = w->hash_link;
	  break;
	}
      p = &(*p)->hash_link;
    }
  w->hash_link = NULL;
}
DNotify::Status
DNotify::watch_dir(const char *notify_dir, dev_t file_dev, ino_t file_ino)
{
  struct stat stat;
  dev_t dir_dev;
  ino_t dir_ino;
  DirWatch *dwatch;
  FileWatch *fw;
    
  if (lstat (notify_dir, &stat) == -1)
      return BAD;
  
  dwatch = lookup_dirwatch(stat.st_dev, stat.st_ino);
  if (!dwatch)
    {
      Log::debug ("New DirWatch for %s (%x %x)\n",
		  notify_dir, (int)stat.st_dev, (int)stat.st_ino);
      dwatch = new DirWatch;
      dwatch->watches = NULL;
      dwatch->hash_link = NULL;
      dwatch->dir_dev = stat.st_dev;
      dwatch->dir_ino = stat.st_ino;
      
      dwatch->fd = open(notify_dir, O_RDONLY);
      fcntl (dwatch->fd, F_SETSIG, SIGRTMIN);
      if (fcntl (dwatch->fd, F_NOTIFY,
                 (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB) 
		  | DN_MULTISHOT) == -1) {
	      return BAD;
      }
      hash_dirwatch (dwatch);
    }
  fw = lookup_filewatch (file_dev, file_ino);
  if (fw && fw->dir_watch == dwatch)
	return OK;
  
  // No old FileWatch, need to add one:
  Log::debug("New FileWatch for %x %x\n", (int)file_dev, (int)file_ino);
  fw = new FileWatch;
  fw->next = dwatch->watches;
  dwatch->watches = fw;
  fw->file_dev = file_dev;
  fw->file_ino = file_ino;
  fw->dir_watch = dwatch;
  hash_filewatch(fw);
  return OK;
}
char *
dirname_dup (const char *name)
{
  char *copy = strdup(name);
  char *res = dirname(copy);
  res = strdup(res);
  free (copy);
  return res;
}
DNotify::Status
DNotify::express(const char *name, struct stat *status)
{
    struct stat stat;
    char *notify_dir;
    int res;
    Status s;
    dev_t dev;
    ino_t ino;
    Log::debug("express() name: %s\n", name);
    if (!is_active())
	return BAD;
    if (::lstat (name, &stat) == -1)
      return BAD;
    dev = stat.st_dev;
    ino = stat.st_ino;
    
    if ((stat.st_mode & S_IFMT) != S_IFDIR)
	notify_dir = dirname_dup (name);
    else
	notify_dir = (char *)name;
    s = watch_dir (notify_dir, dev, ino);
    if (notify_dir != name)
        free (notify_dir);
    if (s)
      return s;
    // Check for a race condition; if someone removed or changed the
    // file at the same time that we are expressing interest in it,
    // revoke the interest so we don't get notifications about changes
    // to a recycled inode that we don't otherwise care about.
    //
    struct stat st;
    if (status == NULL) {
	status = &st;
    }
    if (::lstat(name, status) == -1) {
	Log::perror("stat on \"%s\" failed", name);
	revoke(name, stat.st_dev, stat.st_ino);
	return BAD;
    }
    if (status->st_dev != stat.st_dev
	|| status->st_ino != stat.st_ino) {
	Log::error("File \"%s\" changed between express and stat",
		   name);
	revoke(name, stat.st_dev, stat.st_ino);
	return BAD;
    }	
    Log::debug("told dnotify to monitor \"%s\" = dev %d/%d, ino %d", name,
	       major(status->st_dev), minor(status->st_dev),
	       status->st_ino);
    return OK;
}
DNotify::Status
DNotify::revoke(const char *name, dev_t dev, ino_t ino)
{
    FileWatch *fwatch;
    DirWatch *dwatch;
    
    Log::debug("revoke() name: %s, dev: %x, ino: %x\n", name, dev, ino);
    if (!is_active())
	return BAD;
    // Lookup FileWatch by dev:ino, and its DirWatch.
    fwatch = lookup_filewatch (dev, ino);
    if (fwatch == NULL)
	return BAD;
    
    dwatch = fwatch->dir_watch;
    
    // delete FileWatch, if last FileWatch: close fd, delete DirWatch
    Log::debug ("Destroying FileWatch for (%x %x)\n",
		(int)fwatch->file_dev, (int)fwatch->file_ino);
    FileWatch **p;
    for (p=&dwatch->watches; *p; p=&(*p)->next)
    {
      if (*p == fwatch)
	{
	  *p = (*p)->next;
	  break;
	}
    }
    unhash_filewatch(fwatch);
    delete fwatch;
    if (dwatch->watches == NULL)
      {
	Log::debug ("Destroying DirWatch for (%x %x)\n",
		    (int)dwatch->dir_dev, (int)dwatch->dir_ino);
	close(dwatch->fd);
	unhash_dirwatch(dwatch);
	delete dwatch;
      }
  
    return OK;
}
void
DNotify::all_watches_changed(void)
{
  int i;
  FileWatch *fw;
  for (i=0; i<FILE_HASHSIZE; i++)
  {
      fw = file_hash[i];
      while (fw)
      {
	  (*ehandler)(fw->file_dev, fw->file_ino, CHANGE);
	  fw = fw->hash_link;
      }
  }
}
void
DNotify::read_handler(int fd, void *)
{
    static char readbuf[5000];
    DirWatch *dw;
    FileWatch *fw;
    int snap_queue_tail;
    int last_fd;
    int rc = read(fd, readbuf, sizeof readbuf);
    queue_changed = 0;
    if (rc < 0)
        Log::perror("pipe read");
    else if (queue_overflowed)
    {
	  // There is a *slight* race condition here. Between reading
	  // the queue_overflow flag and resetting it. But it doesn't
	  // matter, since I'm gonna handle the overflow after reseting
	  // anyway.
	  queue_overflowed = false;
	  // We're soon gonna check all watches anyway, so
	  // get rid of the current queue
	  queue_head = queue_tail;
	  
	  all_watches_changed ();
    }
    else
    {
	// Don't read events that happen later than
	// the initial read. (Otherwise skipping fd's
	// might miss some changes).
	snap_queue_tail = queue_tail;
	last_fd = -1;
	while (queue_head != snap_queue_tail)
	{
	    fd = change_queue[queue_head];
	    queue_head = (queue_head + 1) % QUEUESIZE;
	    // Skip multiple changes to the same fd
	    if (fd != last_fd)
	    {
		dw = lookup_dirwatch (fd);
		if (dw)
		{
		    int n_watches, i;
		    ChangeEventData *data;
		    
		    Log::debug("dnotify said dev %d/%d, ino %ld changed",
			       major(dw->dir_dev), minor(dw->dir_dev), dw->dir_ino);
		    
		    n_watches = 0;
		    for (fw=dw->watches; fw; fw=fw->next)
			n_watches++;
		    
		    data = new ChangeEventData[n_watches];
		    i = 0;
		    for (fw=dw->watches; fw; fw=fw->next)
		    {
			data[i].file_dev = fw->file_dev;
			data[i].file_ino = fw->file_ino;
			i++;
		    }
		    for (i = 0; i < n_watches; i++)
		    {
			(*ehandler)(data[i].file_dev, data[i].file_ino, CHANGE);
		    }
		    
		    delete[] data;
		}
	    }
	    last_fd = fd;
	}
    }
}
Line 0    Link Here 
//  Copyright (C) 2001 Red Hat, Inc.  All Rights Reserved.
//  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
//
//  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.
#ifndef DNotify_included
#define DNotify_included
#include "config.h"
#include "Monitor.h"
#include <signal.h>
//  DNotify is an object encapsulating the dnotify linux fcntl.
//  It "emulates" the IMon interface.
//  There can only be one instantiation of the DNotify object.
//
//  The user of this object uses express() and revoke() to
//  express/revoke interest in a file.  There is also
//  a callback, the EventHandler.  When an dnotify event comes in,
//  the EventHandler is called.
//
//  The user of the DNotify object is the Interest class.
class DNotify : public Monitor {
public:
    DNotify(EventHandler h);
    ~DNotify();
    static bool is_active();
    virtual Status express(const char *name, struct stat *stat_return);
    virtual Status revoke(const char *name, dev_t dev, ino_t ino);
private:
    struct FileWatch;
    struct DirWatch;
    struct ChangeEventData;
  
    //  Class Variables
    enum { QUEUESIZE = 1024 };
    static int pipe_write_fd;
    static int pipe_read_fd;
    static int change_queue[QUEUESIZE];
    static volatile sig_atomic_t DNotify::queue_overflowed;
    static volatile sig_atomic_t DNotify::queue_changed;
    static volatile int queue_head; // Only modified by read handler
    static volatile int queue_tail; // Only modified by signal handler
    static EventHandler ehandler;
    static void overflow_signal_handler(int sig, siginfo_t *si, void *data);
    static void signal_handler(int sig, siginfo_t *si, void *data);
    static void read_handler(int fd, void *closure);
 
    enum { DIR_HASHSIZE = 367 };
    static DirWatch *dir_hash[DIR_HASHSIZE];
    enum { FILE_HASHSIZE = 823 };
    static FileWatch *file_hash[FILE_HASHSIZE];
    static DirWatch **dir_hashchain(int fd)
			  { return &dir_hash[(unsigned) (fd) % DIR_HASHSIZE]; }
    static FileWatch **file_hashchain(dev_t d, ino_t i)
			  { return &file_hash[(unsigned) (d+i) % FILE_HASHSIZE]; }
    static DirWatch *lookup_dirwatch (int fd);
    static DirWatch *lookup_dirwatch (dev_t dir_dev, ino_t dir_ino);
    static FileWatch *lookup_filewatch (dev_t file_dev, ino_t file_ino);
    static void hash_dirwatch(DirWatch *w);
    static void hash_filewatch(FileWatch *w);
    static void unhash_dirwatch(DirWatch *w);
    static void unhash_filewatch(FileWatch *w);
    static Status watch_dir(const char *notify_dir, dev_t file_dev, ino_t file_ino);
    static void all_watches_changed(void);
    
    DNotify(const DNotify&);			// Do not copy
    DNotify & operator = (const DNotify&);	//  or assign.
};
#endif /* !IMon_included */
 Lines 42-53    Link Here 
#include "Event.h"
#include "Event.h"
#include "FileSystem.h"
#include "FileSystem.h"
#include "IMon.h"
#include "IMon.h"
#include "DNotify.h"
#include "Log.h"
#include "Log.h"
#include "Pollster.h"
#include "Pollster.h"
#include "timeval.h"
#include "timeval.h"
Interest *Interest::hashtable[];
Interest *Interest::hashtable[];
IMon      Interest::imon(imon_handler);
#ifdef USE_DNOTIFY 
static DNotify dnotify(Interest::monitor_handler);
Monitor * Interest::monitor = &dnotify;
#else
static IMon imon(Interest::monitor_handler);
Monitor * Interest::monitor = &imon;
#endif
bool      Interest::xtab_verification = true;
bool      Interest::xtab_verification = true;
Interest::Interest(const char *name, FileSystem *fs, in_addr host, ExportVerification ev)
Interest::Interest(const char *name, FileSystem *fs, in_addr host, ExportVerification ev)
 Lines 60-69    Link Here 
      mypath_exported_to_host(ev == NO_VERIFY_EXPORTED)
      mypath_exported_to_host(ev == NO_VERIFY_EXPORTED)
{
{
    memset(&old_stat, 0, sizeof(old_stat)); 
    memset(&old_stat, 0, sizeof(old_stat)); 
    IMon::Status s = IMon::BAD;
    s = imon.express(name, &old_stat);
    Monitor::Status s = Monitor::BAD;
    if (s != IMon::OK)
    s = monitor->express(name, &old_stat);
    if (s != Monitor::OK)
    {   int rc = lstat(name, &old_stat);
    {   int rc = lstat(name, &old_stat);
	if (rc < 0)
	if (rc < 0)
	{   Log::info("can't lstat %s", name);
	{   Log::info("can't lstat %s", name);
 Lines 100-106    Link Here 
    }
    }
#endif
#endif
    if (exported_to_host()) fs->ll_monitor(this, s == IMon::OK);
    if (exported_to_host()) fs->ll_monitor(this, s == Monitor::OK);
}
}
Interest::~Interest()
Interest::~Interest()
 Lines 128-134    Link Here 
		pp = &p->hashlink;	// move to next element
		pp = &p->hashlink;	// move to next element
	    }
	    }
	if (!found_same)
	if (!found_same)
	    (void) imon.revoke(name(), dev, ino);
	  (void) monitor->revoke(name(), dev, ino);
    }
    }
}
}
 Lines 147-153    Link Here 
        // Express interest.
        // Express interest.
        IMon::Status s = IMon::BAD;
        IMon::Status s = IMon::BAD;
	s = imon.express(name(), NULL);
	s = monitor->express(name(), NULL);
        if (s != IMon::OK) {
        if (s != IMon::OK) {
            return true;
            return true;
        }
        }
 Lines 248-270    Link Here 
}
}
void
void
Interest::imon_handler(dev_t device, ino_t inumber, int event)
Interest::monitor_handler(dev_t device, ino_t inumber, int event)
{
{
    assert(device || inumber);
    assert(device || inumber);
    for (Interest *p = *hashchain(device, inumber), *next = p; p; p = next)
    for (Interest *p = *hashchain(device, inumber), *next = p; p; p = next)
    {	next = p->hashlink;
    {	next = p->hashlink;
	if (p->ino == inumber && p->dev == device)
	if (p->ino == inumber && p->dev == device)
	{   if (event == IMon::EXEC)
	  {   if (event == Monitor::EXEC)
	    {   p->cur_exec_state = EXECUTING;
	    {   p->cur_exec_state = EXECUTING;
		(void) p->report_exec_state();
		(void) p->report_exec_state();
	    }
	    }
	    else if (event == IMon::EXIT)
	    else if (event == Monitor::EXIT)
	    {   p->cur_exec_state = NOT_EXECUTING;
	    {   p->cur_exec_state = NOT_EXECUTING;
		(void) p->report_exec_state();
		(void) p->report_exec_state();
	    }
	    }
	    else
	    else
	    {   assert(event == IMon::CHANGE);
	    {   assert(event == Monitor::CHANGE);
		p->scan();
		p->scan();
	    }
	    }
	}
	}
 Lines 180-182    Link Here 
/* Define to `int' if <sys/types.h> doesn't define. */
/* Define to `int' if <sys/types.h> doesn't define. */
#undef uid_t
#undef uid_t
/* Define to 1 if you have F_NOTIFY fcntl */
#undef USE_DNOTIFY
 Lines 34-40    Link Here 
AC_HEADER_DIRENT
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 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])
if test "$have_sys_imon_h"; then
# Test for the linux dnotify fcntl
AC_MSG_CHECKING([for dnotify fcntl support])
AC_TRY_COMPILE([
#define _GNU_SOURCE  
#include <fcntl.h>
#include <unistd.h>
],
[ int fd = 1;
  fcntl (fd, F_NOTIFY, (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB)
                       |DN_MULTISHOT);
], have_dnotify=yes, have_dnotify=no)
use_dnotify=false
AC_MSG_RESULT($have_dnotify)
if test "$have_dnotify"; then
        MONITOR_FUNCS=IMonNone
        AC_DEFINE([USE_DNOTIFY], [], [Use dnotify])
	use_dnotify=true
elif test "$have_sys_imon_h"; then
	MONITOR_FUNCS=IMonIRIX
	MONITOR_FUNCS=IMonIRIX
elif test "$have_linux_imon_h"; then
elif test "$have_linux_imon_h"; then
	MONITOR_FUNCS=IMonLinux
	MONITOR_FUNCS=IMonLinux
 Lines 42-47    Link Here 
	MONITOR_FUNCS=IMonNone
	MONITOR_FUNCS=IMonNone
fi
fi
AC_SUBST(MONITOR_FUNCS)
AC_SUBST(MONITOR_FUNCS)
AM_CONDITIONAL(USE_DNOTIFY, $use_dnotify)
# Checks for typedefs, structures, and compiler characteristics.
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
AC_HEADER_STDBOOL
 Lines 24-33    Link Here 
#define IMon_included
#define IMon_included
#include "config.h"
#include "config.h"
#include <sys/stat.h>
#include "Monitor.h"
#include <sys/types.h>
#include "Boolean.h"
struct stat;
struct stat;
 Lines 41-65    Link Here 
//
//
//  The user of the IMon object is the Interest class.
//  The user of the IMon object is the Interest class.
class IMon {
class IMon : public Monitor {
public:
public:
    enum Status { OK = 0, BAD = -1 };
    enum Event { EXEC, EXIT, CHANGE };
    typedef void (*EventHandler)(dev_t, ino_t, int event);
    IMon(EventHandler h);
    IMon(EventHandler h);
    ~IMon();
    ~IMon();
    static bool is_active();
    static bool is_active();
    Status express(const char *name, struct stat *stat_return);
    virtual Status express(const char *name, struct stat *stat_return);
    Status revoke(const char *name, dev_t dev, ino_t ino);
    virtual Status revoke(const char *name, dev_t dev, ino_t ino);
private:
private:
    //  Class Variables
    //  Class Variables
    static int imonfd;
    static int imonfd;
 Lines 32-38    Link Here 
class Event;
class Event;
class FileSystem;
class FileSystem;
class IMon;
class Monitor;
struct stat;
struct stat;
//  Interest -- abstract base class for filesystem entities of interest.
//  Interest -- abstract base class for filesystem entities of interest.
 Lines 74-80    Link Here 
    //  Public Class Method
    //  Public Class Method
    static void imon_handler(dev_t, ino_t, int event);
    static void monitor_handler(dev_t, ino_t, int event);
    static void enable_xtab_verification(bool enable);
    static void enable_xtab_verification(bool enable);
 Lines 121-127    Link Here 
    //  Class Variables
    //  Class Variables
    static IMon imon;
    static Monitor *monitor;
    static Interest *hashtable[HASHSIZE];
    static Interest *hashtable[HASHSIZE];
    static bool xtab_verification;
    static bool xtab_verification;
 Lines 71-77    Link Here 
  main.c++ \
  main.c++ \
  timeval.c++ \
  timeval.c++ \
  timeval.h \
  timeval.h \
  @MONITOR_FUNCS@.c++
  Monitor.h \
  DNotify.h \
  DNotify.c++ \
  @MONITOR_FUNCS@.c++ 
EXTRA_famd_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++
EXTRA_famd_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++ DNotify.c++ \
  DNotify.h Monitor.h
Line 0    Link Here 
//  Copyright (C) 2001 Red Hat, Inc.  All Rights Reserved.
//  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
//  
//  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.
#ifndef Monitor_included
#define Monitor_included
#include "config.h"
#include <sys/stat.h>
#include <sys/types.h>
struct stat;
//  Monitor is an abstract baseclass for differend file monitoring
//  systems. The original system used was IMon, and the Montor API
//  is heavily influenced by that.
//  There can only be one instantiation of the Monitor object.
//
//  The user of this object uses express() and revoke() to
//  express/revoke interest in a file to imon.  There is also
//  a callback, the EventHandler.  When an event comes in,
//  the EventHandler is called.
//
//  The main implementers of the Monitor class is IMon and DNotify
class Monitor {
public:
    enum Status { OK = 0, BAD = -1 };
    enum Event { EXEC, EXIT, CHANGE };
    typedef void (*EventHandler)(dev_t, ino_t, int event);
    virtual Status express(const char *name, struct stat *stat_return) = 0;
    virtual Status revoke(const char *name, dev_t dev, ino_t ino) = 0;
};
#endif /* !Monitor_included */