chiark / gitweb /
Install manpage
[innduct.git] / filemon.c
1 /*
2  *  innduct
3  *  tailing reliable realtime streaming feeder for inn
4  *  filemon.c - file monitoring (inotify, kqueue, poll, etc.)
5  *
6  *  Copyright (C) 2010 Ian Jackson <ijackson@chiark.greenend.org.uk>
7  * 
8  *  This program is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 3 of the License, or
11  *  (at your option) any later version.
12  * 
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  * 
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  *  (I believe that when you compile and link this as part of the inn2
22  *  build, with the Makefile runes I have provided, all the libraries
23  *  and files which end up included in innduct are licence-compatible
24  *  with GPLv3.  If not then please let me know.  -Ian Jackson.)
25  */
26
27 #include "innduct.h"
28
29 /*---------- filemon implemented with inotify ----------*/
30
31 #if defined(HAVE_SYS_INOTIFY_H) && !defined(HAVE_FILEMON)
32 #define HAVE_FILEMON
33
34 #include <sys/inotify.h>
35
36 static int filemon_inotify_fd;
37 static int filemon_inotify_wdmax;
38 static InputFile **filemon_inotify_wd2ipf;
39
40 struct Filemon_Perfile {
41   int wd;
42 };
43
44 static void filemon_method_startfile(InputFile *ipf, Filemon_Perfile *pf) {
45   int wd= inotify_add_watch(filemon_inotify_fd, ipf->path, IN_MODIFY);
46   if (wd < 0) sysdie("inotify_add_watch %s", ipf->path);
47
48   if (wd >= filemon_inotify_wdmax) {
49     int newmax= wd+2;
50     filemon_inotify_wd2ipf= xrealloc(filemon_inotify_wd2ipf,
51                                  sizeof(*filemon_inotify_wd2ipf) * newmax);
52     memset(filemon_inotify_wd2ipf + filemon_inotify_wdmax, 0,
53            sizeof(*filemon_inotify_wd2ipf) * (newmax - filemon_inotify_wdmax));
54     filemon_inotify_wdmax= newmax;
55   }
56
57   assert(!filemon_inotify_wd2ipf[wd]);
58   filemon_inotify_wd2ipf[wd]= ipf;
59
60   dbg("filemon inotify startfile %p wd=%d wdmax=%d",
61       ipf, wd, filemon_inotify_wdmax);
62
63   pf->wd= wd;
64 }
65
66 static void filemon_method_stopfile(InputFile *ipf, Filemon_Perfile *pf) {
67   int wd= pf->wd;
68   dbg("filemon inotify stopfile %p wd=%d", ipf, wd);
69   int r= inotify_rm_watch(filemon_inotify_fd, wd);
70   if (r) syscrash("inotify_rm_watch");
71   filemon_inotify_wd2ipf[wd]= 0;
72 }
73
74 static void *filemon_inotify_readable(oop_source *lp, int fd,
75                                       oop_event e, void *u) {
76   struct inotify_event iev;
77   for (;;) {
78     int r= read(filemon_inotify_fd, &iev, sizeof(iev));
79     if (r==-1) {
80       if (isewouldblock(errno)) break;
81       syscrash("read from inotify master");
82     } else if (r==sizeof(iev)) {
83       assert(iev.wd >= 0 && iev.wd < filemon_inotify_wdmax);
84     } else {
85       crash("inotify read %d bytes wanted struct of %d", r, (int)sizeof(iev));
86     }
87     InputFile *ipf= filemon_inotify_wd2ipf[iev.wd];
88     /*dbg("filemon inotify readable read %p wd=%d", ipf, iev.wd);*/
89     tailing_make_readable(ipf);
90   }
91   return OOP_CONTINUE;
92 }
93
94 int filemon_method_init(void) {
95   filemon_inotify_fd= inotify_init();
96   if (filemon_inotify_fd<0) {
97     syswarn("filemon/inotify: inotify_init failed");
98     return 0;
99   }
100   xsetnonblock(filemon_inotify_fd, 1);
101   loop->on_fd(loop, filemon_inotify_fd, OOP_READ, filemon_inotify_readable, 0);
102
103   dbg("filemon inotify init filemon_inotify_fd=%d", filemon_inotify_fd);
104   return 1;
105 }
106
107 void filemon_method_dump_info(FILE *f) {
108   int i;
109   fprintf(f,"inotify");
110   DUMPV("%d",,filemon_inotify_fd);
111   DUMPV("%d",,filemon_inotify_wdmax);
112   for (i=0; i<filemon_inotify_wdmax; i++)
113     fprintf(f," wd2ipf[%d]=%p\n", i, filemon_inotify_wd2ipf[i]);
114 }
115
116 #endif /* HAVE_INOTIFY && !HAVE_FILEMON */
117
118 /*---------- filemon dummy implementation ----------*/
119
120 #if !defined(HAVE_FILEMON)
121
122 struct Filemon_Perfile { int dummy; };
123
124 int filemon_method_init(void) {
125   warn("filemon/dummy: no filemon method compiled in");
126   return 0;
127 }
128 static void filemon_method_startfile(InputFile *ipf, Filemon_Perfile *pf) { }
129 static void filemon_method_stopfile(InputFile *ipf, Filemon_Perfile *pf) { }
130 void filemon_method_dump_info(FILE *f) { fprintf(f,"dummy\n"); }
131
132 #endif /* !HAVE_FILEMON */
133
134 /*---------- filemon generic interface ----------*/
135
136 void filemon_start(InputFile *ipf) {
137   assert(!ipf->filemon);
138
139   NEW(ipf->filemon);
140   filemon_method_startfile(ipf, ipf->filemon);
141 }
142
143 void filemon_stop(InputFile *ipf) {
144   if (!ipf->filemon) return;
145   filemon_method_stopfile(ipf, ipf->filemon);
146   free(ipf->filemon);
147   ipf->filemon= 0;
148 }
149