chiark / gitweb /
wip split into multiple files and make compile
[inn-innduct.git] / filemon.c
1 /*---------- filemon implemented with inotify ----------*/
2
3 #if defined(HAVE_SYS_INOTIFY_H) && !defined(HAVE_FILEMON)
4 #define HAVE_FILEMON
5
6 #include <sys/inotify.h>
7
8 static int filemon_inotify_fd;
9 static int filemon_inotify_wdmax;
10 static InputFile **filemon_inotify_wd2ipf;
11
12 struct Filemon_Perfile {
13   int wd;
14 };
15
16 static void filemon_method_startfile(InputFile *ipf, Filemon_Perfile *pf) {
17   int wd= inotify_add_watch(filemon_inotify_fd, ipf->path, IN_MODIFY);
18   if (wd < 0) sysdie("inotify_add_watch %s", ipf->path);
19
20   if (wd >= filemon_inotify_wdmax) {
21     int newmax= wd+2;
22     filemon_inotify_wd2ipf= xrealloc(filemon_inotify_wd2ipf,
23                                  sizeof(*filemon_inotify_wd2ipf) * newmax);
24     memset(filemon_inotify_wd2ipf + filemon_inotify_wdmax, 0,
25            sizeof(*filemon_inotify_wd2ipf) * (newmax - filemon_inotify_wdmax));
26     filemon_inotify_wdmax= newmax;
27   }
28
29   assert(!filemon_inotify_wd2ipf[wd]);
30   filemon_inotify_wd2ipf[wd]= ipf;
31
32   dbg("filemon inotify startfile %p wd=%d wdmax=%d",
33       ipf, wd, filemon_inotify_wdmax);
34
35   pf->wd= wd;
36 }
37
38 static void filemon_method_stopfile(InputFile *ipf, Filemon_Perfile *pf) {
39   int wd= pf->wd;
40   dbg("filemon inotify stopfile %p wd=%d", ipf, wd);
41   int r= inotify_rm_watch(filemon_inotify_fd, wd);
42   if (r) syscrash("inotify_rm_watch");
43   filemon_inotify_wd2ipf[wd]= 0;
44 }
45
46 static void *filemon_inotify_readable(oop_source *lp, int fd,
47                                       oop_event e, void *u) {
48   struct inotify_event iev;
49   for (;;) {
50     int r= read(filemon_inotify_fd, &iev, sizeof(iev));
51     if (r==-1) {
52       if (isewouldblock(errno)) break;
53       syscrash("read from inotify master");
54     } else if (r==sizeof(iev)) {
55       assert(iev.wd >= 0 && iev.wd < filemon_inotify_wdmax);
56     } else {
57       crash("inotify read %d bytes wanted struct of %d", r, (int)sizeof(iev));
58     }
59     InputFile *ipf= filemon_inotify_wd2ipf[iev.wd];
60     /*dbg("filemon inotify readable read %p wd=%d", ipf, iev.wd);*/
61     tailing_make_readable(ipf);
62   }
63   return OOP_CONTINUE;
64 }
65
66 static int filemon_method_init(void) {
67   filemon_inotify_fd= inotify_init();
68   if (filemon_inotify_fd<0) {
69     syswarn("filemon/inotify: inotify_init failed");
70     return 0;
71   }
72   xsetnonblock(filemon_inotify_fd, 1);
73   loop->on_fd(loop, filemon_inotify_fd, OOP_READ, filemon_inotify_readable, 0);
74
75   dbg("filemon inotify init filemon_inotify_fd=%d", filemon_inotify_fd);
76   return 1;
77 }
78
79 static void filemon_method_dump_info(FILE *f) {
80   int i;
81   fprintf(f,"inotify");
82   DUMPV("%d",,filemon_inotify_fd);
83   DUMPV("%d",,filemon_inotify_wdmax);
84   for (i=0; i<filemon_inotify_wdmax; i++)
85     fprintf(f," wd2ipf[%d]=%p\n", i, filemon_inotify_wd2ipf[i]);
86 }
87
88 #endif /* HAVE_INOTIFY && !HAVE_FILEMON */
89
90 /*---------- filemon dummy implementation ----------*/
91
92 #if !defined(HAVE_FILEMON)
93
94 struct Filemon_Perfile { int dummy; };
95
96 static int filemon_method_init(void) {
97   warn("filemon/dummy: no filemon method compiled in");
98   return 0;
99 }
100 static void filemon_method_startfile(InputFile *ipf, Filemon_Perfile *pf) { }
101 static void filemon_method_stopfile(InputFile *ipf, Filemon_Perfile *pf) { }
102 static void filemon_method_dump_info(FILE *f) { fprintf(f,"dummy\n"); }
103
104 #endif /* !HAVE_FILEMON */
105
106 /*---------- filemon generic interface ----------*/
107
108 static void filemon_start(InputFile *ipf) {
109   assert(!ipf->filemon);
110
111   NEW(ipf->filemon);
112   filemon_method_startfile(ipf, ipf->filemon);
113 }
114
115 static void filemon_stop(InputFile *ipf) {
116   if (!ipf->filemon) return;
117   filemon_method_stopfile(ipf, ipf->filemon);
118   free(ipf->filemon);
119   ipf->filemon= 0;
120 }
121