--- /dev/null 2003-09-15 15:40:47.000000000 +0200 +++ fam-2.6.10/src/DNotify.c++ 2004-02-04 11:13:04.000000000 +0100 @@ -0,0 +1,655 @@ +// 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 + +#include +#include +#include +#include +#include +#include +#include + +#include "DNotify.h" + +#include "Interest.h" +#include "Log.h" +#include "Scheduler.h" +#include "alloc.h" + + +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; + int n_dir_watches; + dev_t file_dev; + ino_t file_ino; + FileWatch *hash_link; + + FileWatch(void) { + dir_watch = NULL; + n_dir_watches = 0; + } + + void add_dir_watch (DirWatch *w); + bool has_dir_watch (DirWatch *w); +}; + + +struct DNotify::DirWatch +{ + class FileWatchList { + public: + struct Node { + FileWatch *watch; + Node *next; + }; + + Node *first; + + FileWatchList(void) { + first = NULL; + } + + void prepend(FileWatch *watch); + void remove(FileWatch *watch); + bool empty(void); + int len(void); + + }; + + dev_t dir_dev; + ino_t dir_ino; + int fd; + + DirWatch *hash_link; + FileWatchList file_watches; +}; + +struct DNotify::ChangeEventData +{ + dev_t file_dev; + ino_t file_ino; +}; + +bool +DNotify::FileWatch::has_dir_watch (DirWatch *w) +{ + int i; + + for (i = 0; i < n_dir_watches; i++) { + if (dir_watch[i] == w) + return true; + } + return false; +} + + +void +DNotify::FileWatch::add_dir_watch (DirWatch *w) +{ + n_dir_watches++; + dir_watch = (DirWatch **)realloc (dir_watch, n_dir_watches*sizeof(DirWatch *)); + dir_watch[n_dir_watches-1] = w; +} + +bool +DNotify::DirWatch::FileWatchList::empty(void) +{ + return first == NULL; +} + +int +DNotify::DirWatch::FileWatchList::len(void) +{ + int i; + Node *n; + + i = 0; + n = first; + while (n) { + i++; + n = n->next; + } + + return i; +} + + +void +DNotify::DirWatch::FileWatchList::prepend(FileWatch *watch) +{ + Node *node; + + node = new Node; + node->watch = watch; + node->next = first; + + first = node; +} + +void +DNotify::DirWatch::FileWatchList::remove(FileWatch *watch) { + Node *l, *prev; + + l = first; + prev = NULL; + while (l) { + if (l->watch == watch) { + if (prev) + prev->next = l->next; + else + first = l->next; + + delete l; + break; + } + prev = l; + l = prev->next; + } +} + + +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;idir_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->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); + fcntl (dwatch->fd, F_NOTIFY, + (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB) | DN_MULTISHOT); + hash_dirwatch (dwatch); + } + + fw = lookup_filewatch(file_dev, file_ino); + if (fw) { + if (!fw->has_dir_watch(dwatch)) { + fw->add_dir_watch(dwatch); + dwatch->file_watches.prepend(fw); + } + 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->add_dir_watch(dwatch); + dwatch->file_watches.prepend(fw); + fw->file_dev = file_dev; + fw->file_ino = file_ino; + 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; + int i; + + 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; + + // 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); + for (i = 0; i < fwatch->n_dir_watches; i++) { + dwatch = fwatch->dir_watch[i]; + dwatch->file_watches.remove (fwatch); + + if (dwatch->file_watches.empty()) { + Log::debug ("Destroying DirWatch for (%x %x)\n", + (int)dwatch->dir_dev, (int)dwatch->dir_ino); + close(dwatch->fd); + unhash_dirwatch(dwatch); + delete dwatch; + } + } + unhash_filewatch(fwatch); + delete fwatch; + + return OK; +} + + +void +DNotify::all_watches_changed(void) +{ + int i; + FileWatch *fw; + + for (i=0; ifile_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; + DirWatch::FileWatchList::Node *n; + + Log::debug("dnotify said dev %d/%d, ino %ld changed", + major(dw->dir_dev), minor(dw->dir_dev), dw->dir_ino); + + n_watches = dw->file_watches.len(); + data = new ChangeEventData[n_watches]; + + i = 0; + for (n=dw->file_watches.first; n; n=n->next) { + data[i].file_dev = n->watch->file_dev; + data[i].file_ino = n->watch->file_ino; + i++; + } + assert(i == n_watches); + + for (i = 0; i < n_watches; i++) { + (*ehandler)(data[i].file_dev, data[i].file_ino, CHANGE); + } + + delete[] data; + } + } + last_fd = fd; + } + } +} + --- /dev/null 2003-09-15 15:40:47.000000000 +0200 +++ fam-2.6.10/src/DNotify.h 2004-02-03 18:30:26.000000000 +0100 @@ -0,0 +1,98 @@ +// 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 + +// 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 */ + + --- fam-2.6.10/src/IMon.h.dnotify 2003-04-15 06:21:34.000000000 +0200 +++ fam-2.6.10/src/IMon.h 2004-02-03 18:30:26.000000000 +0100 @@ -24,10 +24,7 @@ #define IMon_included #include "config.h" -#include -#include - -#include "Boolean.h" +#include "Monitor.h" struct stat; @@ -41,25 +38,18 @@ // // The user of the IMon object is the Interest class. -class IMon { +class IMon : public Monitor { 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(); static bool is_active(); - Status express(const char *name, struct stat *stat_return); - Status revoke(const char *name, dev_t dev, ino_t ino); + virtual Status express(const char *name, struct stat *stat_return); + virtual Status revoke(const char *name, dev_t dev, ino_t ino); private: - // Class Variables static int imonfd; --- fam-2.6.10/src/Interest.c++.dnotify 2003-04-15 06:21:34.000000000 +0200 +++ fam-2.6.10/src/Interest.c++ 2004-02-03 18:30:26.000000000 +0100 @@ -43,12 +43,21 @@ #include "Event.h" #include "FileSystem.h" #include "IMon.h" +#include "DNotify.h" #include "Log.h" #include "Pollster.h" #include "timeval.h" 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; Interest::Interest(const char *name, FileSystem *fs, in_addr host, ExportVerification ev) @@ -60,11 +69,11 @@ myhost(host), mypath_exported_to_host(ev == NO_VERIFY_EXPORTED) { - memset(&old_stat, 0, sizeof(old_stat)); - IMon::Status s = IMon::BAD; - - s = imon.express(name, &old_stat); - if (s != IMon::OK) + memset(&old_stat, 0, sizeof(old_stat)); + + Monitor::Status s = Monitor::BAD; + s = monitor->express(name, &old_stat); + if (s != Monitor::OK) { int rc = lstat(name, &old_stat); if (rc < 0) { Log::info("can't lstat %s", name); @@ -101,7 +110,7 @@ } #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() @@ -129,7 +138,7 @@ pp = &p->hashlink; // move to next element } if (!found_same) - (void) imon.revoke(name(), dev, ino); + (void) monitor->revoke(name(), dev, ino); } } @@ -148,7 +157,7 @@ // Express interest. IMon::Status s = IMon::BAD; - s = imon.express(name(), NULL); + s = monitor->express(name(), NULL); if (s != IMon::OK) { return true; } @@ -249,23 +258,23 @@ } 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); for (Interest *p = *hashchain(device, inumber), *next = p; p; p = next) { next = p->hashlink; if (p->ino == inumber && p->dev == device) - { if (event == IMon::EXEC) + { if (event == Monitor::EXEC) { p->cur_exec_state = EXECUTING; (void) p->report_exec_state(); } - else if (event == IMon::EXIT) + else if (event == Monitor::EXIT) { p->cur_exec_state = NOT_EXECUTING; (void) p->report_exec_state(); } else - { assert(event == IMon::CHANGE); + { assert(event == Monitor::CHANGE); p->scan(); } } --- fam-2.6.10/src/Interest.h.dnotify 2003-04-15 06:21:34.000000000 +0200 +++ fam-2.6.10/src/Interest.h 2004-02-03 18:30:26.000000000 +0100 @@ -32,7 +32,7 @@ class Event; class FileSystem; -class IMon; +class Monitor; struct stat; // Interest -- abstract base class for filesystem entities of interest. @@ -74,7 +74,7 @@ // 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); @@ -121,7 +121,7 @@ // Class Variables - static IMon imon; + static Monitor *monitor; static Interest *hashtable[HASHSIZE]; static bool xtab_verification; --- fam-2.6.10/src/Makefile.am.dnotify 2003-04-15 06:21:26.000000000 +0200 +++ fam-2.6.10/src/Makefile.am 2004-02-03 18:30:26.000000000 +0100 @@ -3,6 +3,12 @@ sbin_PROGRAMS = famd +if USE_DNOTIFY +DNOTIFY_FILES = DNotify.c++ +else +DNOTIFY_FILES = +endif + famd_SOURCES = \ Activity.c++ \ Activity.h \ @@ -20,6 +26,7 @@ Directory.h \ DirectoryScanner.c++ \ DirectoryScanner.h \ + DNotify.h \ Event.c++ \ Event.h \ File.c++ \ @@ -48,6 +55,7 @@ NFSFileSystem.h \ NetConnection.c++ \ NetConnection.h \ + Monitor.h \ Pollster.c++ \ Pollster.h \ Request.h \ @@ -72,7 +80,8 @@ main.c++ \ timeval.c++ \ timeval.h \ - @MONITOR_FUNCS@.c++ + @MONITOR_FUNCS@.c++ \ + $(DNOTIFY_FILES) -EXTRA_famd_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++ +EXTRA_famd_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++ DNotify.c++ --- /dev/null 2003-09-15 15:40:47.000000000 +0200 +++ fam-2.6.10/src/Monitor.h 2004-02-03 18:30:26.000000000 +0100 @@ -0,0 +1,57 @@ +// 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 +#include + +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 */ --- fam-2.6.10/include/BTree.h.dnotify 2003-04-15 06:21:19.000000000 +0200 +++ fam-2.6.10/include/BTree.h 2004-02-03 18:30:26.000000000 +0100 @@ -271,7 +271,7 @@ n += that->n + 1; link[n] = that->link[that->n]; that->n = 0; - that->link[0] = NULL; + that->link[0] = 0; } /////////////////////////////////////////////////////////////////////////////// @@ -280,7 +280,7 @@ template BTree::BTree() - : root(NULL), npairs(0) + : root(0), npairs(0) { assert(!(fanout % 2)); } @@ -407,7 +407,7 @@ BTree::Closure BTree::insert(Node *p, const Key& key, const Value& value) { - if (!p) return Closure(key, value, NULL); + if (!p) return Closure(key, value, 0); // If you're running Purify on a client linking with libfam, and it says // that line is causing a 3-byte UMR for BTree::insert() in // FAMNextEvent() ("Reading 8 bytes from 0x... on the stack (3 bytes at @@ -475,7 +475,7 @@ case UNDER: if (root->n == 0) { Node *nr = root->link[0]; - root->link[0] = NULL; // don't delete subtree + root->link[0] = 0; // don't delete subtree delete root; root = nr; } @@ -507,8 +507,8 @@ Node *cp = p->link[i]; assert(cp); - Node *rp = i < p->n ? p->link[i + 1] : NULL; - Node *lp = i > 0 ? p->link[i - 1] : NULL; + Node *rp = i < p->n ? p->link[i + 1] : 0; + Node *lp = i > 0 ? p->link[i - 1] : 0; assert(!rp || rp->n >= fanout / 2); assert(!lp || lp->n >= fanout / 2); --- fam-2.6.10/configure.ac.dnotify 2003-04-15 08:05:00.000000000 +0200 +++ fam-2.6.10/configure.ac 2004-02-03 18:30:26.000000000 +0100 @@ -100,6 +100,24 @@ 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]) +dnl +dnl Test for the linux dnotify fcntl +dnl +AC_MSG_CHECKING([for dnotify fcntl support]) +fam_save_cppflags="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" +AC_TRY_COMPILE([ +#define _GNU_SOURCE +#include +#include +], +[ 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 +CPPFLAGS="$pango_save_cppflags" +AC_MSG_RESULT($have_dnotify) + if test "$have_sys_imon_h"; then MONITOR_FUNCS=IMonIRIX elif test "$have_linux_imon_h"; then @@ -122,9 +140,14 @@ elif test "$have_linux_imon_h"; then MONITOR_FUNCS=IMonLinux else + if test "$have_dnotify" = "yes"; then + use_dnotify=true + AC_DEFINE([USE_DNOTIFY], [1], [Define if the system has the dnotify fcntl and it's gonna be used.]) + fi MONITOR_FUNCS=IMonNone fi AC_SUBST(MONITOR_FUNCS) +AM_CONDITIONAL(USE_DNOTIFY, $use_dnotify) # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STDBOOL