chiark / gitweb /
wip split into multiple files and make compile
[innduct.git] / filemon.c
diff --git a/filemon.c b/filemon.c
new file mode 100644 (file)
index 0000000..9a362db
--- /dev/null
+++ b/filemon.c
@@ -0,0 +1,121 @@
+/*---------- filemon implemented with inotify ----------*/
+
+#if defined(HAVE_SYS_INOTIFY_H) && !defined(HAVE_FILEMON)
+#define HAVE_FILEMON
+
+#include <sys/inotify.h>
+
+static int filemon_inotify_fd;
+static int filemon_inotify_wdmax;
+static InputFile **filemon_inotify_wd2ipf;
+
+struct Filemon_Perfile {
+  int wd;
+};
+
+static void filemon_method_startfile(InputFile *ipf, Filemon_Perfile *pf) {
+  int wd= inotify_add_watch(filemon_inotify_fd, ipf->path, IN_MODIFY);
+  if (wd < 0) sysdie("inotify_add_watch %s", ipf->path);
+
+  if (wd >= filemon_inotify_wdmax) {
+    int newmax= wd+2;
+    filemon_inotify_wd2ipf= xrealloc(filemon_inotify_wd2ipf,
+                                sizeof(*filemon_inotify_wd2ipf) * newmax);
+    memset(filemon_inotify_wd2ipf + filemon_inotify_wdmax, 0,
+          sizeof(*filemon_inotify_wd2ipf) * (newmax - filemon_inotify_wdmax));
+    filemon_inotify_wdmax= newmax;
+  }
+
+  assert(!filemon_inotify_wd2ipf[wd]);
+  filemon_inotify_wd2ipf[wd]= ipf;
+
+  dbg("filemon inotify startfile %p wd=%d wdmax=%d",
+      ipf, wd, filemon_inotify_wdmax);
+
+  pf->wd= wd;
+}
+
+static void filemon_method_stopfile(InputFile *ipf, Filemon_Perfile *pf) {
+  int wd= pf->wd;
+  dbg("filemon inotify stopfile %p wd=%d", ipf, wd);
+  int r= inotify_rm_watch(filemon_inotify_fd, wd);
+  if (r) syscrash("inotify_rm_watch");
+  filemon_inotify_wd2ipf[wd]= 0;
+}
+
+static void *filemon_inotify_readable(oop_source *lp, int fd,
+                                     oop_event e, void *u) {
+  struct inotify_event iev;
+  for (;;) {
+    int r= read(filemon_inotify_fd, &iev, sizeof(iev));
+    if (r==-1) {
+      if (isewouldblock(errno)) break;
+      syscrash("read from inotify master");
+    } else if (r==sizeof(iev)) {
+      assert(iev.wd >= 0 && iev.wd < filemon_inotify_wdmax);
+    } else {
+      crash("inotify read %d bytes wanted struct of %d", r, (int)sizeof(iev));
+    }
+    InputFile *ipf= filemon_inotify_wd2ipf[iev.wd];
+    /*dbg("filemon inotify readable read %p wd=%d", ipf, iev.wd);*/
+    tailing_make_readable(ipf);
+  }
+  return OOP_CONTINUE;
+}
+
+static int filemon_method_init(void) {
+  filemon_inotify_fd= inotify_init();
+  if (filemon_inotify_fd<0) {
+    syswarn("filemon/inotify: inotify_init failed");
+    return 0;
+  }
+  xsetnonblock(filemon_inotify_fd, 1);
+  loop->on_fd(loop, filemon_inotify_fd, OOP_READ, filemon_inotify_readable, 0);
+
+  dbg("filemon inotify init filemon_inotify_fd=%d", filemon_inotify_fd);
+  return 1;
+}
+
+static void filemon_method_dump_info(FILE *f) {
+  int i;
+  fprintf(f,"inotify");
+  DUMPV("%d",,filemon_inotify_fd);
+  DUMPV("%d",,filemon_inotify_wdmax);
+  for (i=0; i<filemon_inotify_wdmax; i++)
+    fprintf(f," wd2ipf[%d]=%p\n", i, filemon_inotify_wd2ipf[i]);
+}
+
+#endif /* HAVE_INOTIFY && !HAVE_FILEMON */
+
+/*---------- filemon dummy implementation ----------*/
+
+#if !defined(HAVE_FILEMON)
+
+struct Filemon_Perfile { int dummy; };
+
+static int filemon_method_init(void) {
+  warn("filemon/dummy: no filemon method compiled in");
+  return 0;
+}
+static void filemon_method_startfile(InputFile *ipf, Filemon_Perfile *pf) { }
+static void filemon_method_stopfile(InputFile *ipf, Filemon_Perfile *pf) { }
+static void filemon_method_dump_info(FILE *f) { fprintf(f,"dummy\n"); }
+
+#endif /* !HAVE_FILEMON */
+
+/*---------- filemon generic interface ----------*/
+
+static void filemon_start(InputFile *ipf) {
+  assert(!ipf->filemon);
+
+  NEW(ipf->filemon);
+  filemon_method_startfile(ipf, ipf->filemon);
+}
+
+static void filemon_stop(InputFile *ipf) {
+  if (!ipf->filemon) return;
+  filemon_method_stopfile(ipf, ipf->filemon);
+  free(ipf->filemon);
+  ipf->filemon= 0;
+}
+