You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1006 lines
27 KiB
1006 lines
27 KiB
# --- SDE-COPYRIGHT-NOTE-BEGIN --- |
|
# This copyright note is auto-generated by ./scripts/Create-CopyPatch. |
|
# |
|
# Filename: package/.../fam/fam-2.7.0-dnotify-1.patch |
|
# Copyright (C) 2010 The OpenSDE Project |
|
# |
|
# More information can be found in the files COPYING and README. |
|
# |
|
# This patch file is dual-licensed. It is available under the license the |
|
# patched project is licensed under, as long as it is an OpenSource license |
|
# as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms |
|
# of the GNU General Public License as published by the Free Software |
|
# Foundation; either version 2 of the License, or (at your option) any later |
|
# version. |
|
# --- SDE-COPYRIGHT-NOTE-END --- |
|
|
|
Submitted By: Jim Gifford (jim at linuxfromscratch dot org) |
|
Date: 2004-03-15 |
|
Initial Package Version: Jim Gifford |
|
Origin: Debian Maintainer of FAM |
|
Description: Dnotify Patch for FAM 2.7.0 |
|
|
|
diff -Naur fam-2.7.0.orig/config.h.in fam-2.7.0/config.h.in |
|
--- fam-2.7.0.orig/config.h.in 2003-01-20 00:40:15.000000000 +0000 |
|
+++ fam-2.7.0/config.h.in 2004-03-15 21:31:34.553059530 +0000 |
|
@@ -180,3 +180,6 @@ |
|
|
|
/* Define to `int' if <sys/types.h> doesn't define. */ |
|
#undef uid_t |
|
+ |
|
+/* Define to 1 if you have F_NOTIFY fcntl */ |
|
+#undef USE_DNOTIFY |
|
diff -Naur fam-2.7.0.orig/configure.ac fam-2.7.0/configure.ac |
|
--- fam-2.7.0.orig/configure.ac 2003-11-26 19:47:59.000000000 +0000 |
|
+++ fam-2.7.0/configure.ac 2004-03-15 21:31:34.556058981 +0000 |
|
@@ -33,7 +33,26 @@ |
|
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]) |
|
|
|
-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 |
|
elif test "$have_linux_imon_h"; then |
|
MONITOR_FUNCS=IMonLinux |
|
@@ -41,6 +60,7 @@ |
|
MONITOR_FUNCS=IMonNone |
|
fi |
|
AC_SUBST(MONITOR_FUNCS) |
|
+AM_CONDITIONAL(USE_DNOTIFY, $use_dnotify) |
|
|
|
# Checks for typedefs, structures, and compiler characteristics. |
|
AC_HEADER_STDBOOL |
|
diff -Naur fam-2.7.0.orig/src/DNotify.c++ fam-2.7.0/src/DNotify.c++ |
|
--- fam-2.7.0.orig/src/DNotify.c++ 1970-01-01 00:00:00.000000000 +0000 |
|
+++ fam-2.7.0/src/DNotify.c++ 2004-03-15 21:31:34.542061543 +0000 |
|
@@ -0,0 +1,582 @@ |
|
+// 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; |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
diff -Naur fam-2.7.0.orig/src/DNotify.h fam-2.7.0/src/DNotify.h |
|
--- fam-2.7.0.orig/src/DNotify.h 1970-01-01 00:00:00.000000000 +0000 |
|
+++ fam-2.7.0/src/DNotify.h 2004-03-15 21:31:34.546060811 +0000 |
|
@@ -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 <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 */ |
|
+ |
|
+ |
|
diff -Naur fam-2.7.0.orig/src/IMon.h fam-2.7.0/src/IMon.h |
|
--- fam-2.7.0.orig/src/IMon.h 2003-01-18 14:18:12.000000000 +0000 |
|
+++ fam-2.7.0/src/IMon.h 2004-03-15 21:31:34.558058615 +0000 |
|
@@ -24,10 +24,7 @@ |
|
#define IMon_included |
|
|
|
#include "config.h" |
|
-#include <sys/stat.h> |
|
-#include <sys/types.h> |
|
- |
|
-#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; |
|
diff -Naur fam-2.7.0.orig/src/Interest.c++ fam-2.7.0/src/Interest.c++ |
|
--- fam-2.7.0.orig/src/Interest.c++ 2003-01-18 14:18:12.000000000 +0000 |
|
+++ fam-2.7.0/src/Interest.c++ 2004-03-15 21:31:34.550060079 +0000 |
|
@@ -42,12 +42,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,10 +69,10 @@ |
|
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) |
|
+ 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); |
|
@@ -100,7 +109,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() |
|
@@ -128,7 +137,7 @@ |
|
pp = &p->hashlink; // move to next element |
|
} |
|
if (!found_same) |
|
- (void) imon.revoke(name(), dev, ino); |
|
+ (void) monitor->revoke(name(), dev, ino); |
|
} |
|
} |
|
|
|
@@ -147,7 +156,7 @@ |
|
|
|
// Express interest. |
|
IMon::Status s = IMon::BAD; |
|
- s = imon.express(name(), NULL); |
|
+ s = monitor->express(name(), NULL); |
|
if (s != IMon::OK) { |
|
return true; |
|
} |
|
@@ -248,23 +257,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(); |
|
} |
|
} |
|
diff -Naur fam-2.7.0.orig/src/Interest.h fam-2.7.0/src/Interest.h |
|
--- fam-2.7.0.orig/src/Interest.h 2003-01-18 14:18:12.000000000 +0000 |
|
+++ fam-2.7.0/src/Interest.h 2004-03-15 21:31:34.560058249 +0000 |
|
@@ -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; |
|
|
|
diff -Naur fam-2.7.0.orig/src/Makefile.am fam-2.7.0/src/Makefile.am |
|
--- fam-2.7.0.orig/src/Makefile.am 2003-01-19 12:00:17.000000000 +0000 |
|
+++ fam-2.7.0/src/Makefile.am 2004-03-15 21:31:34.562057882 +0000 |
|
@@ -71,7 +71,11 @@ |
|
main.c++ \ |
|
timeval.c++ \ |
|
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 |
|
|
|
diff -Naur fam-2.7.0.orig/src/Monitor.h fam-2.7.0/src/Monitor.h |
|
--- fam-2.7.0.orig/src/Monitor.h 1970-01-01 00:00:00.000000000 +0000 |
|
+++ fam-2.7.0/src/Monitor.h 2004-03-15 21:31:34.564057516 +0000 |
|
@@ -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 <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 */
|
|
|