Magellan Linux

Annotation of /trunk/fam/patches/fam-2.7.0-dnotify.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 144 - (hide annotations) (download)
Tue May 8 20:06:05 2007 UTC (17 years, 1 month ago) by niro
File size: 26419 byte(s)
-import

1 niro 144 --- fam-2.7.0/src/DNotify.c++ 2004-01-30 00:00:00.000000000 +0100
2     +++ fam-2.7.0.dnotify/src/DNotify.c++ 2004-01-30 00:00:00.000000000 +0100
3     @@ -0,0 +1,582 @@
4     +// Copyright (C) 2001 Red Hat, Inc. All Rights Reserved.
5     +// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved.
6     +//
7     +// This program is free software; you can redistribute it and/or modify it
8     +// under the terms of version 2 of the GNU General Public License as
9     +// published by the Free Software Foundation.
10     +//
11     +// This program is distributed in the hope that it would be useful, but
12     +// WITHOUT ANY WARRANTY; without even the implied warranty of
13     +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any
14     +// license provided herein, whether implied or otherwise, is limited to
15     +// this program in accordance with the express provisions of the GNU
16     +// General Public License. Patent licenses, if any, provided herein do not
17     +// apply to combinations of this program with other product or programs, or
18     +// any other product whatsoever. This program is distributed without any
19     +// warranty that the program is delivered free of the rightful claim of any
20     +// third person by way of infringement or the like. See the GNU General
21     +// Public License for more details.
22     +//
23     +// You should have received a copy of the GNU General Public License along
24     +// with this program; if not, write the Free Software Foundation, Inc., 59
25     +// Temple Place - Suite 330, Boston MA 02111-1307, USA.
26     +
27     +#define _GNU_SOURCE
28     +#include <fcntl.h>
29     +
30     +#include <string.h>
31     +#include <signal.h>
32     +#include <stdio.h>
33     +#include <unistd.h>
34     +#include <sys/types.h>
35     +#include <sys/stat.h>
36     +#include <libgen.h>
37     +
38     +#include "DNotify.h"
39     +
40     +#include "Interest.h"
41     +#include "Log.h"
42     +#include "Scheduler.h"
43     +#include <memory>
44     +
45     +
46     +int DNotify::pipe_write_fd = -2;
47     +int DNotify::pipe_read_fd = -2;
48     +volatile sig_atomic_t DNotify::queue_overflowed = 0;
49     +volatile sig_atomic_t DNotify::queue_changed = 0;
50     +int DNotify::change_queue[QUEUESIZE];
51     +volatile int DNotify::queue_head = 0; // Only modified by read handler
52     +volatile int DNotify::queue_tail = 0; // Only modified by signal handler
53     +DNotify::EventHandler DNotify::ehandler;
54     +
55     +DNotify::DirWatch *DNotify::dir_hash[DIR_HASHSIZE];
56     +DNotify::FileWatch *DNotify::file_hash[FILE_HASHSIZE];
57     +
58     +struct DNotify::FileWatch
59     +{
60     + DirWatch *dir_watch;
61     + dev_t file_dev;
62     + ino_t file_ino;
63     + FileWatch *next; // The DirWatch.watches list
64     + FileWatch *hash_link;
65     +};
66     +
67     +struct DNotify::DirWatch
68     +{
69     + int fd;
70     + dev_t dir_dev;
71     + ino_t dir_ino;
72     +
73     + DirWatch *hash_link;
74     + FileWatch *watches;
75     +};
76     +
77     +struct DNotify::ChangeEventData
78     +{
79     + dev_t file_dev;
80     + ino_t file_ino;
81     +};
82     +
83     +DNotify::DNotify(EventHandler h)
84     +{
85     + assert(ehandler == NULL);
86     + ehandler = h;
87     +}
88     +
89     +DNotify::~DNotify()
90     +{
91     + if (pipe_read_fd >= 0)
92     + {
93     + // Tell the scheduler.
94     +
95     + (void) Scheduler::remove_read_handler(pipe_read_fd);
96     +
97     + // Close the pipe.
98     +
99     + if (close(pipe_read_fd) < 0)
100     + Log::perror("can't pipe read end");
101     + else
102     + Log::debug("closed pipe read end");
103     +
104     + if (close(pipe_write_fd) < 0)
105     + Log::perror("can't pipe write end");
106     + else
107     + Log::debug("closed pipe write end");
108     + pipe_read_fd = -1;
109     + }
110     + ehandler = NULL;
111     +}
112     +
113     +void
114     +DNotify::overflow_signal_handler(int sig, siginfo_t *si, void *data)
115     +{
116     + char c = 'x';
117     +
118     + {
119     + char *str = "*************** overflow sigqueue ***********************\n";
120     + write (STDERR_FILENO, str, strlen(str));
121     + }
122     +
123     + if (!queue_overflowed)
124     + {
125     + queue_overflowed = 1;
126     + // Trigger the read handler
127     + write(pipe_write_fd, &c, 1);
128     + }
129     +}
130     +
131     +void
132     +DNotify::signal_handler(int sig, siginfo_t *si, void *data)
133     +{
134     + int left;
135     + char c = 'x';
136     +
137     + if (queue_head <= queue_tail)
138     + left = (QUEUESIZE + queue_head) - queue_tail;
139     + else
140     + left = queue_head - queue_tail;
141     +
142     + // Must leave at least one item unused to see difference
143     + // Betweeen empty and full
144     + if (left <= 1)
145     + {
146     + queue_overflowed = 1;
147     + {
148     + char *str = "*************** overflow famqueue ****************\n";
149     + write (STDERR_FILENO, str, strlen(str));
150     + }
151     + }
152     + else
153     + {
154     + change_queue[queue_tail] = si->si_fd;
155     + queue_tail = (queue_tail + 1) % QUEUESIZE;
156     + }
157     +
158     + if (!queue_changed)
159     + {
160     + queue_changed = 1;
161     + // Trigger the read handler
162     + write(pipe_write_fd, &c, 1);
163     + }
164     +}
165     +
166     +bool
167     +DNotify::is_active()
168     +{
169     + if (pipe_read_fd == -2)
170     + {
171     + int filedes[2];
172     + int res;
173     +
174     + res = pipe (filedes);
175     + if (res >= 0)
176     + { Log::debug("opened pipe");
177     + pipe_read_fd = filedes[0];
178     + pipe_write_fd = filedes[1];
179     +
180     + // Setup signal handler:
181     + struct sigaction act;
182     +
183     + act.sa_sigaction = signal_handler;
184     + sigemptyset(&act.sa_mask);
185     + act.sa_flags = SA_SIGINFO;
186     + sigaction(SIGRTMIN, &act, NULL);
187     +
188     + // When the RT queue overflows we get a SIGIO
189     + act.sa_sigaction = overflow_signal_handler;
190     + sigemptyset(&act.sa_mask);
191     + sigaction(SIGIO, &act, NULL);
192     +
193     + (void) Scheduler::install_read_handler(pipe_read_fd, read_handler, NULL);
194     + }
195     + }
196     + return pipe_read_fd >= 0;
197     +}
198     +
199     +DNotify::DirWatch *
200     +DNotify::lookup_dirwatch (int fd)
201     +{
202     + DirWatch **p;
203     + DirWatch *w;
204     +
205     + p = dir_hashchain (fd);
206     +
207     + while (*p)
208     + {
209     + w = *p;
210     +
211     + if (w->fd == fd)
212     + return w;
213     +
214     + p = &w->hash_link;
215     + }
216     +
217     + return *p;
218     +}
219     +
220     +// This colud be made faster by using another hash table.
221     +// But it's not that bad, since it is only used by express/revoke
222     +DNotify::DirWatch *
223     +DNotify::lookup_dirwatch (dev_t dir_dev, ino_t dir_ino)
224     +{
225     + DirWatch *p;
226     + int i;
227     +
228     + for (i=0;i<DIR_HASHSIZE;i++)
229     + {
230     + p = dir_hash[i];
231     +
232     + while (p)
233     + {
234     + if (p->dir_dev == dir_dev && p->dir_ino == dir_ino)
235     + return p;
236     +
237     + p = p->hash_link;
238     + }
239     + }
240     +
241     + return NULL;
242     +}
243     +
244     +DNotify::FileWatch *
245     +DNotify::lookup_filewatch (dev_t dev, ino_t ino)
246     +{
247     + FileWatch **p;
248     + FileWatch *w;
249     +
250     + p = file_hashchain (dev, ino);
251     +
252     + while (*p)
253     + {
254     + w = *p;
255     +
256     + if (w->file_dev == dev && w->file_ino == ino)
257     + return w;
258     +
259     + p = &w->hash_link;
260     + }
261     +
262     + return *p;
263     +}
264     +
265     +// Make sure w is not already in the hash table before calling
266     +// this function.
267     +void
268     +DNotify::hash_dirwatch(DirWatch *w)
269     +{
270     + DirWatch **p;
271     + p = dir_hashchain (w->fd);
272     + w->hash_link = *p;
273     + *p = w;
274     +}
275     +
276     +// Make sure w is not already in the hash table before calling
277     +// this function.
278     +void
279     +DNotify::hash_filewatch(FileWatch *w)
280     +{
281     + FileWatch **p;
282     + p = file_hashchain (w->file_dev, w->file_ino);
283     + w->hash_link = *p;
284     + *p = w;
285     +}
286     +
287     +void
288     +DNotify::unhash_dirwatch(DirWatch *w)
289     +{
290     + DirWatch **p;
291     +
292     + p = dir_hashchain (w->fd);
293     +
294     + while (*p)
295     + {
296     + if (*p == w)
297     + {
298     + *p = w->hash_link;
299     + break;
300     + }
301     + p = &(*p)->hash_link;
302     + }
303     + w->hash_link = NULL;
304     +}
305     +
306     +void
307     +DNotify::unhash_filewatch(FileWatch *w)
308     +{
309     + FileWatch **p;
310     +
311     + p = file_hashchain (w->file_dev, w->file_ino);
312     +
313     + while (*p)
314     + {
315     + if (*p == w)
316     + {
317     + *p = w->hash_link;
318     + break;
319     + }
320     + p = &(*p)->hash_link;
321     + }
322     + w->hash_link = NULL;
323     +}
324     +
325     +DNotify::Status
326     +DNotify::watch_dir(const char *notify_dir, dev_t file_dev, ino_t file_ino)
327     +{
328     + struct stat stat;
329     + dev_t dir_dev;
330     + ino_t dir_ino;
331     + DirWatch *dwatch;
332     + FileWatch *fw;
333     +
334     + if (lstat (notify_dir, &stat) == -1)
335     + return BAD;
336     +
337     + dwatch = lookup_dirwatch(stat.st_dev, stat.st_ino);
338     + if (!dwatch)
339     + {
340     + Log::debug ("New DirWatch for %s (%x %x)\n",
341     + notify_dir, (int)stat.st_dev, (int)stat.st_ino);
342     + dwatch = new DirWatch;
343     + dwatch->watches = NULL;
344     + dwatch->hash_link = NULL;
345     + dwatch->dir_dev = stat.st_dev;
346     + dwatch->dir_ino = stat.st_ino;
347     +
348     + dwatch->fd = open(notify_dir, O_RDONLY);
349     + fcntl (dwatch->fd, F_SETSIG, SIGRTMIN);
350     + if (fcntl (dwatch->fd, F_NOTIFY,
351     + (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB)
352     + | DN_MULTISHOT) == -1) {
353     + return BAD;
354     + }
355     + hash_dirwatch (dwatch);
356     + }
357     +
358     + fw = lookup_filewatch (file_dev, file_ino);
359     + if (fw && fw->dir_watch == dwatch)
360     + return OK;
361     +
362     + // No old FileWatch, need to add one:
363     + Log::debug("New FileWatch for %x %x\n", (int)file_dev, (int)file_ino);
364     + fw = new FileWatch;
365     + fw->next = dwatch->watches;
366     + dwatch->watches = fw;
367     + fw->file_dev = file_dev;
368     + fw->file_ino = file_ino;
369     + fw->dir_watch = dwatch;
370     + hash_filewatch(fw);
371     + return OK;
372     +}
373     +
374     +char *
375     +dirname_dup (const char *name)
376     +{
377     + char *copy = strdup(name);
378     + char *res = dirname(copy);
379     + res = strdup(res);
380     + free (copy);
381     + return res;
382     +}
383     +
384     +DNotify::Status
385     +DNotify::express(const char *name, struct stat *status)
386     +{
387     + struct stat stat;
388     + char *notify_dir;
389     + int res;
390     + Status s;
391     + dev_t dev;
392     + ino_t ino;
393     +
394     + Log::debug("express() name: %s\n", name);
395     +
396     + if (!is_active())
397     + return BAD;
398     +
399     + if (::lstat (name, &stat) == -1)
400     + return BAD;
401     +
402     + dev = stat.st_dev;
403     + ino = stat.st_ino;
404     +
405     + if ((stat.st_mode & S_IFMT) != S_IFDIR)
406     + notify_dir = dirname_dup (name);
407     + else
408     + notify_dir = (char *)name;
409     +
410     + s = watch_dir (notify_dir, dev, ino);
411     + if (notify_dir != name)
412     + free (notify_dir);
413     + if (s)
414     + return s;
415     +
416     + // Check for a race condition; if someone removed or changed the
417     + // file at the same time that we are expressing interest in it,
418     + // revoke the interest so we don't get notifications about changes
419     + // to a recycled inode that we don't otherwise care about.
420     + //
421     + struct stat st;
422     + if (status == NULL) {
423     + status = &st;
424     + }
425     + if (::lstat(name, status) == -1) {
426     + Log::perror("stat on \"%s\" failed", name);
427     + revoke(name, stat.st_dev, stat.st_ino);
428     + return BAD;
429     + }
430     + if (status->st_dev != stat.st_dev
431     + || status->st_ino != stat.st_ino) {
432     + Log::error("File \"%s\" changed between express and stat",
433     + name);
434     + revoke(name, stat.st_dev, stat.st_ino);
435     + return BAD;
436     + }
437     +
438     + Log::debug("told dnotify to monitor \"%s\" = dev %d/%d, ino %d", name,
439     + major(status->st_dev), minor(status->st_dev),
440     + status->st_ino);
441     + return OK;
442     +}
443     +
444     +DNotify::Status
445     +DNotify::revoke(const char *name, dev_t dev, ino_t ino)
446     +{
447     + FileWatch *fwatch;
448     + DirWatch *dwatch;
449     +
450     + Log::debug("revoke() name: %s, dev: %x, ino: %x\n", name, dev, ino);
451     +
452     + if (!is_active())
453     + return BAD;
454     +
455     + // Lookup FileWatch by dev:ino, and its DirWatch.
456     + fwatch = lookup_filewatch (dev, ino);
457     + if (fwatch == NULL)
458     + return BAD;
459     +
460     + dwatch = fwatch->dir_watch;
461     +
462     + // delete FileWatch, if last FileWatch: close fd, delete DirWatch
463     + Log::debug ("Destroying FileWatch for (%x %x)\n",
464     + (int)fwatch->file_dev, (int)fwatch->file_ino);
465     + FileWatch **p;
466     + for (p=&dwatch->watches; *p; p=&(*p)->next)
467     + {
468     + if (*p == fwatch)
469     + {
470     + *p = (*p)->next;
471     + break;
472     + }
473     + }
474     + unhash_filewatch(fwatch);
475     + delete fwatch;
476     + if (dwatch->watches == NULL)
477     + {
478     + Log::debug ("Destroying DirWatch for (%x %x)\n",
479     + (int)dwatch->dir_dev, (int)dwatch->dir_ino);
480     + close(dwatch->fd);
481     + unhash_dirwatch(dwatch);
482     + delete dwatch;
483     + }
484     +
485     + return OK;
486     +}
487     +
488     +
489     +void
490     +DNotify::all_watches_changed(void)
491     +{
492     + int i;
493     + FileWatch *fw;
494     +
495     + for (i=0; i<FILE_HASHSIZE; i++)
496     + {
497     + fw = file_hash[i];
498     + while (fw)
499     + {
500     + (*ehandler)(fw->file_dev, fw->file_ino, CHANGE);
501     +
502     + fw = fw->hash_link;
503     + }
504     + }
505     +}
506     +
507     +
508     +void
509     +DNotify::read_handler(int fd, void *)
510     +{
511     + static char readbuf[5000];
512     + DirWatch *dw;
513     + FileWatch *fw;
514     + int snap_queue_tail;
515     + int last_fd;
516     +
517     + int rc = read(fd, readbuf, sizeof readbuf);
518     + queue_changed = 0;
519     + if (rc < 0)
520     + Log::perror("pipe read");
521     + else if (queue_overflowed)
522     + {
523     + // There is a *slight* race condition here. Between reading
524     + // the queue_overflow flag and resetting it. But it doesn't
525     + // matter, since I'm gonna handle the overflow after reseting
526     + // anyway.
527     + queue_overflowed = false;
528     +
529     + // We're soon gonna check all watches anyway, so
530     + // get rid of the current queue
531     + queue_head = queue_tail;
532     +
533     + all_watches_changed ();
534     + }
535     + else
536     + {
537     + // Don't read events that happen later than
538     + // the initial read. (Otherwise skipping fd's
539     + // might miss some changes).
540     + snap_queue_tail = queue_tail;
541     + last_fd = -1;
542     + while (queue_head != snap_queue_tail)
543     + {
544     + fd = change_queue[queue_head];
545     + queue_head = (queue_head + 1) % QUEUESIZE;
546     +
547     + // Skip multiple changes to the same fd
548     + if (fd != last_fd)
549     + {
550     + dw = lookup_dirwatch (fd);
551     + if (dw)
552     + {
553     + int n_watches, i;
554     + ChangeEventData *data;
555     +
556     + Log::debug("dnotify said dev %d/%d, ino %ld changed",
557     + major(dw->dir_dev), minor(dw->dir_dev), dw->dir_ino);
558     +
559     + n_watches = 0;
560     + for (fw=dw->watches; fw; fw=fw->next)
561     + n_watches++;
562     +
563     + data = new ChangeEventData[n_watches];
564     +
565     + i = 0;
566     + for (fw=dw->watches; fw; fw=fw->next)
567     + {
568     + data[i].file_dev = fw->file_dev;
569     + data[i].file_ino = fw->file_ino;
570     + i++;
571     + }
572     +
573     + for (i = 0; i < n_watches; i++)
574     + {
575     + (*ehandler)(data[i].file_dev, data[i].file_ino, CHANGE);
576     + }
577     +
578     + delete[] data;
579     + }
580     + }
581     + last_fd = fd;
582     + }
583     + }
584     +}
585     +
586     --- fam-2.7.0/src/DNotify.h 2004-01-30 00:00:00.000000000 +0100
587     +++ fam-2.7.0.dnotify/src/DNotify.h 2004-01-30 00:00:00.000000000 +0100
588     @@ -0,0 +1,98 @@
589     +// Copyright (C) 2001 Red Hat, Inc. All Rights Reserved.
590     +// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved.
591     +//
592     +// This program is free software; you can redistribute it and/or modify it
593     +// under the terms of version 2 of the GNU General Public License as
594     +// published by the Free Software Foundation.
595     +//
596     +// This program is distributed in the hope that it would be useful, but
597     +// WITHOUT ANY WARRANTY; without even the implied warranty of
598     +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any
599     +// license provided herein, whether implied or otherwise, is limited to
600     +// this program in accordance with the express provisions of the GNU
601     +// General Public License. Patent licenses, if any, provided herein do not
602     +// apply to combinations of this program with other product or programs, or
603     +// any other product whatsoever. This program is distributed without any
604     +// warranty that the program is delivered free of the rightful claim of any
605     +// third person by way of infringement or the like. See the GNU General
606     +// Public License for more details.
607     +//
608     +// You should have received a copy of the GNU General Public License along
609     +// with this program; if not, write the Free Software Foundation, Inc., 59
610     +// Temple Place - Suite 330, Boston MA 02111-1307, USA.
611     +
612     +#ifndef DNotify_included
613     +#define DNotify_included
614     +
615     +#include "config.h"
616     +#include "Monitor.h"
617     +#include <signal.h>
618     +
619     +// DNotify is an object encapsulating the dnotify linux fcntl.
620     +// It "emulates" the IMon interface.
621     +// There can only be one instantiation of the DNotify object.
622     +//
623     +// The user of this object uses express() and revoke() to
624     +// express/revoke interest in a file. There is also
625     +// a callback, the EventHandler. When an dnotify event comes in,
626     +// the EventHandler is called.
627     +//
628     +// The user of the DNotify object is the Interest class.
629     +
630     +class DNotify : public Monitor {
631     +public:
632     + DNotify(EventHandler h);
633     + ~DNotify();
634     +
635     + static bool is_active();
636     +
637     + virtual Status express(const char *name, struct stat *stat_return);
638     + virtual Status revoke(const char *name, dev_t dev, ino_t ino);
639     +
640     +private:
641     + struct FileWatch;
642     + struct DirWatch;
643     + struct ChangeEventData;
644     +
645     + // Class Variables
646     + enum { QUEUESIZE = 1024 };
647     + static int pipe_write_fd;
648     + static int pipe_read_fd;
649     + static int change_queue[QUEUESIZE];
650     + static volatile sig_atomic_t DNotify::queue_overflowed;
651     + static volatile sig_atomic_t DNotify::queue_changed;
652     + static volatile int queue_head; // Only modified by read handler
653     + static volatile int queue_tail; // Only modified by signal handler
654     + static EventHandler ehandler;
655     + static void overflow_signal_handler(int sig, siginfo_t *si, void *data);
656     + static void signal_handler(int sig, siginfo_t *si, void *data);
657     + static void read_handler(int fd, void *closure);
658     +
659     + enum { DIR_HASHSIZE = 367 };
660     + static DirWatch *dir_hash[DIR_HASHSIZE];
661     + enum { FILE_HASHSIZE = 823 };
662     + static FileWatch *file_hash[FILE_HASHSIZE];
663     +
664     + static DirWatch **dir_hashchain(int fd)
665     + { return &dir_hash[(unsigned) (fd) % DIR_HASHSIZE]; }
666     + static FileWatch **file_hashchain(dev_t d, ino_t i)
667     + { return &file_hash[(unsigned) (d+i) % FILE_HASHSIZE]; }
668     +
669     + static DirWatch *lookup_dirwatch (int fd);
670     + static DirWatch *lookup_dirwatch (dev_t dir_dev, ino_t dir_ino);
671     + static FileWatch *lookup_filewatch (dev_t file_dev, ino_t file_ino);
672     + static void hash_dirwatch(DirWatch *w);
673     + static void hash_filewatch(FileWatch *w);
674     + static void unhash_dirwatch(DirWatch *w);
675     + static void unhash_filewatch(FileWatch *w);
676     + static Status watch_dir(const char *notify_dir, dev_t file_dev, ino_t file_ino);
677     +
678     + static void all_watches_changed(void);
679     +
680     + DNotify(const DNotify&); // Do not copy
681     + DNotify & operator = (const DNotify&); // or assign.
682     +};
683     +
684     +#endif /* !IMon_included */
685     +
686     +
687     --- fam-2.7.0/src/Interest.c++ 2004-01-30 00:00:00.000000000 +0100
688     +++ fam-2.7.0.dnotify/src/Interest.c++ 2004-01-30 00:00:00.000000000 +0100
689     @@ -42,12 +42,21 @@
690     #include "Event.h"
691     #include "FileSystem.h"
692     #include "IMon.h"
693     +#include "DNotify.h"
694     #include "Log.h"
695     #include "Pollster.h"
696     #include "timeval.h"
697    
698     Interest *Interest::hashtable[];
699     -IMon Interest::imon(imon_handler);
700     +
701     +#ifdef USE_DNOTIFY
702     +static DNotify dnotify(Interest::monitor_handler);
703     +Monitor * Interest::monitor = &dnotify;
704     +#else
705     +static IMon imon(Interest::monitor_handler);
706     +Monitor * Interest::monitor = &imon;
707     +#endif
708     +
709     bool Interest::xtab_verification = true;
710    
711     Interest::Interest(const char *name, FileSystem *fs, in_addr host, ExportVerification ev)
712     @@ -60,10 +69,10 @@
713     mypath_exported_to_host(ev == NO_VERIFY_EXPORTED)
714     {
715     memset(&old_stat, 0, sizeof(old_stat));
716     - IMon::Status s = IMon::BAD;
717    
718     - s = imon.express(name, &old_stat);
719     - if (s != IMon::OK)
720     + Monitor::Status s = Monitor::BAD;
721     + s = monitor->express(name, &old_stat);
722     + if (s != Monitor::OK)
723     { int rc = lstat(name, &old_stat);
724     if (rc < 0)
725     { Log::info("can't lstat %s", name);
726     @@ -100,7 +109,7 @@
727     }
728     #endif
729    
730     - if (exported_to_host()) fs->ll_monitor(this, s == IMon::OK);
731     + if (exported_to_host()) fs->ll_monitor(this, s == Monitor::OK);
732     }
733    
734     Interest::~Interest()
735     @@ -128,7 +137,7 @@
736     pp = &p->hashlink; // move to next element
737     }
738     if (!found_same)
739     - (void) imon.revoke(name(), dev, ino);
740     + (void) monitor->revoke(name(), dev, ino);
741     }
742     }
743    
744     @@ -147,7 +156,7 @@
745    
746     // Express interest.
747     IMon::Status s = IMon::BAD;
748     - s = imon.express(name(), NULL);
749     + s = monitor->express(name(), NULL);
750     if (s != IMon::OK) {
751     return true;
752     }
753     @@ -248,23 +257,23 @@
754     }
755    
756     void
757     -Interest::imon_handler(dev_t device, ino_t inumber, int event)
758     +Interest::monitor_handler(dev_t device, ino_t inumber, int event)
759     {
760     assert(device || inumber);
761    
762     for (Interest *p = *hashchain(device, inumber), *next = p; p; p = next)
763     { next = p->hashlink;
764     if (p->ino == inumber && p->dev == device)
765     - { if (event == IMon::EXEC)
766     + { if (event == Monitor::EXEC)
767     { p->cur_exec_state = EXECUTING;
768     (void) p->report_exec_state();
769     }
770     - else if (event == IMon::EXIT)
771     + else if (event == Monitor::EXIT)
772     { p->cur_exec_state = NOT_EXECUTING;
773     (void) p->report_exec_state();
774     }
775     else
776     - { assert(event == IMon::CHANGE);
777     + { assert(event == Monitor::CHANGE);
778     p->scan();
779     }
780     }
781     --- fam-2.7.0/config.h.in 2003-01-20 01:40:15.000000000 +0100
782     +++ fam-2.7.0.dnotify/config.h.in 2004-01-30 13:50:33.000000000 +0100
783     @@ -180,3 +180,6 @@
784    
785     /* Define to `int' if <sys/types.h> doesn't define. */
786     #undef uid_t
787     +
788     +/* Define to 1 if you have F_NOTIFY fcntl */
789     +#undef USE_DNOTIFY
790     --- fam-2.7.0/configure.ac 2003-11-26 20:47:59.000000000 +0100
791     +++ fam-2.7.0.dnotify/configure.ac 2004-01-30 13:50:33.000000000 +0100
792     @@ -34,7 +34,26 @@
793     AC_HEADER_DIRENT
794     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])
795    
796     -if test "$have_sys_imon_h"; then
797     +# Test for the linux dnotify fcntl
798     +AC_MSG_CHECKING([for dnotify fcntl support])
799     +AC_TRY_COMPILE([
800     +#define _GNU_SOURCE
801     +#include <fcntl.h>
802     +#include <unistd.h>
803     +],
804     +[ int fd = 1;
805     + fcntl (fd, F_NOTIFY, (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB)
806     + |DN_MULTISHOT);
807     +], have_dnotify=yes, have_dnotify=no)
808     +
809     +use_dnotify=false
810     +AC_MSG_RESULT($have_dnotify)
811     +
812     +if test "$have_dnotify"; then
813     + MONITOR_FUNCS=IMonNone
814     + AC_DEFINE([USE_DNOTIFY], [], [Use dnotify])
815     + use_dnotify=true
816     +elif test "$have_sys_imon_h"; then
817     MONITOR_FUNCS=IMonIRIX
818     elif test "$have_linux_imon_h"; then
819     MONITOR_FUNCS=IMonLinux
820     @@ -42,6 +62,7 @@
821     MONITOR_FUNCS=IMonNone
822     fi
823     AC_SUBST(MONITOR_FUNCS)
824     +AM_CONDITIONAL(USE_DNOTIFY, $use_dnotify)
825    
826     # Checks for typedefs, structures, and compiler characteristics.
827     AC_HEADER_STDBOOL
828     --- fam-2.7.0/src/IMon.h 2004-01-30 00:00:00.000000000 +0200
829     +++ fam-2.7.0.dnotify/src/IMon.h 2004-01-30 00:00:00.000000000 +0200
830     @@ -24,10 +24,7 @@
831     #define IMon_included
832    
833     #include "config.h"
834     -#include <sys/stat.h>
835     -#include <sys/types.h>
836     -
837     -#include "Boolean.h"
838     +#include "Monitor.h"
839    
840     struct stat;
841    
842     @@ -41,25 +38,18 @@
843     //
844     // The user of the IMon object is the Interest class.
845    
846     -class IMon {
847     +class IMon : public Monitor {
848    
849     public:
850     -
851     - enum Status { OK = 0, BAD = -1 };
852     - enum Event { EXEC, EXIT, CHANGE };
853     -
854     - typedef void (*EventHandler)(dev_t, ino_t, int event);
855     -
856     IMon(EventHandler h);
857     ~IMon();
858    
859     static bool is_active();
860    
861     - Status express(const char *name, struct stat *stat_return);
862     - Status revoke(const char *name, dev_t dev, ino_t ino);
863     + virtual Status express(const char *name, struct stat *stat_return);
864     + virtual Status revoke(const char *name, dev_t dev, ino_t ino);
865    
866     private:
867     -
868     // Class Variables
869    
870     static int imonfd;
871     --- fam-2.7.0/src/Interest.h 2004-01-30 00:00:00.000000000 +0200
872     +++ fam-2.7.0.dnotify/src/Interest.h 2004-01-30 00:00:00.000000000 +0200
873     @@ -32,7 +32,7 @@
874    
875     class Event;
876     class FileSystem;
877     -class IMon;
878     +class Monitor;
879     struct stat;
880    
881     // Interest -- abstract base class for filesystem entities of interest.
882     @@ -74,7 +74,7 @@
883    
884     // Public Class Method
885    
886     - static void imon_handler(dev_t, ino_t, int event);
887     + static void monitor_handler(dev_t, ino_t, int event);
888    
889     static void enable_xtab_verification(bool enable);
890    
891     @@ -121,7 +121,7 @@
892    
893     // Class Variables
894    
895     - static IMon imon;
896     + static Monitor *monitor;
897     static Interest *hashtable[HASHSIZE];
898     static bool xtab_verification;
899    
900     --- fam-2.7.0/src/Makefile.am 2003-01-19 13:00:17.000000000 +0100
901     +++ fam-2.7.0.dnotify/src/Makefile.am 2004-01-30 13:50:38.000000000 +0100
902     @@ -71,7 +71,11 @@
903     main.c++ \
904     timeval.c++ \
905     timeval.h \
906     - @MONITOR_FUNCS@.c++
907     + Monitor.h \
908     + DNotify.h \
909     + DNotify.c++ \
910     + @MONITOR_FUNCS@.c++
911    
912     -EXTRA_famd_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++
913     +EXTRA_famd_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++ DNotify.c++ \
914     + DNotify.h Monitor.h
915    
916     --- fam-2.7.0/src/Monitor.h 2004-01-30 00:00:00.000000000 +0200
917     +++ fam-2.7.0.dnotify/src/Monitor.h 2004-01-30 00:00:00.000000000 +0200
918     @@ -0,0 +1,57 @@
919     +// Copyright (C) 2001 Red Hat, Inc. All Rights Reserved.
920     +// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved.
921     +//
922     +// This program is free software; you can redistribute it and/or modify it
923     +// under the terms of version 2 of the GNU General Public License as
924     +// published by the Free Software Foundation.
925     +//
926     +// This program is distributed in the hope that it would be useful, but
927     +// WITHOUT ANY WARRANTY; without even the implied warranty of
928     +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any
929     +// license provided herein, whether implied or otherwise, is limited to
930     +// this program in accordance with the express provisions of the GNU
931     +// General Public License. Patent licenses, if any, provided herein do not
932     +// apply to combinations of this program with other product or programs, or
933     +// any other product whatsoever. This program is distributed without any
934     +// warranty that the program is delivered free of the rightful claim of any
935     +// third person by way of infringement or the like. See the GNU General
936     +// Public License for more details.
937     +//
938     +// You should have received a copy of the GNU General Public License along
939     +// with this program; if not, write the Free Software Foundation, Inc., 59
940     +// Temple Place - Suite 330, Boston MA 02111-1307, USA.
941     +
942     +#ifndef Monitor_included
943     +#define Monitor_included
944     +
945     +#include "config.h"
946     +#include <sys/stat.h>
947     +#include <sys/types.h>
948     +
949     +struct stat;
950     +
951     +// Monitor is an abstract baseclass for differend file monitoring
952     +// systems. The original system used was IMon, and the Montor API
953     +// is heavily influenced by that.
954     +// There can only be one instantiation of the Monitor object.
955     +//
956     +// The user of this object uses express() and revoke() to
957     +// express/revoke interest in a file to imon. There is also
958     +// a callback, the EventHandler. When an event comes in,
959     +// the EventHandler is called.
960     +//
961     +// The main implementers of the Monitor class is IMon and DNotify
962     +
963     +class Monitor {
964     +public:
965     +
966     + enum Status { OK = 0, BAD = -1 };
967     + enum Event { EXEC, EXIT, CHANGE };
968     +
969     + typedef void (*EventHandler)(dev_t, ino_t, int event);
970     +
971     + virtual Status express(const char *name, struct stat *stat_return) = 0;
972     + virtual Status revoke(const char *name, dev_t dev, ino_t ino) = 0;
973     +};
974     +
975     +#endif /* !Monitor_included */