Linux file watcher: report only relevant unwatchable roots
authorRoman Shevchenko <roman.shevchenko@jetbrains.com>
Mon, 16 Jul 2012 16:01:13 +0000 (18:01 +0200)
committerRoman Shevchenko <roman.shevchenko@jetbrains.com>
Mon, 16 Jul 2012 16:02:13 +0000 (18:02 +0200)
bin/linux/fsnotifier
bin/linux/fsnotifier64
native/fsNotifier/linux/main.c

index 0e72f246193735ac42d2f75d3e9b876bca16bf42..715b78f2d45fadecb37bb98741bfb23b28b2498e 100755 (executable)
Binary files a/bin/linux/fsnotifier and b/bin/linux/fsnotifier differ
index 74de18e5c244cb16d63492fdaf2639bd20820567..13dfd34a954923b1cb87f54ab51042a68de4f113 100755 (executable)
Binary files a/bin/linux/fsnotifier64 and b/bin/linux/fsnotifier64 differ
index a3a24294c32cda2e7ea3a528b5461af8bb21d3b6..ce9d6c275ea7ca948184cf9391a579a4adaff4b5 100644 (file)
@@ -66,8 +66,8 @@ static void main_loop();
 static bool read_input();
 static bool update_roots(array* new_roots);
 static void unregister_roots();
-static bool register_roots(array* new_roots, array* unwatchable);
-static bool unwatchable_mounts(array* mounts);
+static bool register_roots(array* new_roots, array* unwatchable, array* mounts);
+static array* unwatchable_mounts();
 static void inotify_callback(char* path, int event);
 static void output(const char* format, ...);
 
@@ -249,6 +249,7 @@ static bool update_roots(array* new_roots) {
   userlog(LOG_INFO, "updating roots (curr:%d, new:%d)", array_size(roots), array_size(new_roots));
 
   unregister_roots();
+
   if (array_size(new_roots) == 0) {
     output("UNWATCHEABLE\n#\n");
     array_delete(new_roots);
@@ -261,17 +262,16 @@ static bool update_roots(array* new_roots) {
     return true;
   }
 
-  array* unwatchable = array_create(20);
-  CHECK_NULL(unwatchable, false);
-  if (!unwatchable_mounts(unwatchable)) {
+  array* mounts = unwatchable_mounts();
+  if (mounts == NULL) {
     return false;
   }
 
-  if (!register_roots(new_roots, unwatchable)) {
+  array* unwatchable = array_create(20);
+  if (!register_roots(new_roots, unwatchable, mounts)) {
     return false;
   }
 
-  // todo: sort/optimize list
   output("UNWATCHEABLE\n");
   for (int i=0; i<array_size(unwatchable); i++) {
     char* s = array_get(unwatchable, i);
@@ -281,6 +281,7 @@ static bool update_roots(array* new_roots) {
   output("#\n");
 
   array_delete_vs_data(unwatchable);
+  array_delete_vs_data(mounts);
   array_delete(new_roots);
 
   return true;
@@ -298,11 +299,29 @@ static void unregister_roots() {
 }
 
 
-static bool register_roots(array* new_roots, array* unwatchable) {
+static bool register_roots(array* new_roots, array* unwatchable, array* mounts) {
   for (int i=0; i<array_size(new_roots); i++) {
     char* new_root = array_get(new_roots, i);
     userlog(LOG_INFO, "registering root: %s", new_root);
+
+    char* root = new_root;
+    if (*root == '|') ++root;
+    char* skip = NULL;
+    for (int j=0; j<array_size(mounts); j++) {
+      char* mount = array_get(mounts, j);
+      if (strncmp(mount, root, strlen(mount)) == 0) {
+        skip = root;
+        break;
+      }
+    }
+    if (skip != NULL) {
+      CHECK_NULL(array_push(unwatchable, skip), false);
+      continue;
+    }
+
+    // todo: consider a mount point under a watch root
     int id = watch(new_root, unwatchable);
+
     if (id == ERR_ABORT) {
       return false;
     }
@@ -327,6 +346,7 @@ static bool register_roots(array* new_roots, array* unwatchable) {
   return true;
 }
 
+
 static bool is_watchable(const char* dev, const char* mnt, const char* fs) {
   // don't watch special and network filesystems
   return !(strncmp(mnt, "/dev", 4) == 0 || strncmp(mnt, "/proc", 5) == 0 || strncmp(mnt, "/sys", 4) == 0 ||
@@ -335,16 +355,19 @@ static bool is_watchable(const char* dev, const char* mnt, const char* fs) {
 
 #define MTAB_DELIMS " \t"
 
-static bool unwatchable_mounts(array* mounts) {
+static array* unwatchable_mounts() {
   FILE* mtab = fopen("/etc/mtab", "r");
   if (mtab == NULL) {
     mtab = fopen("/proc/mounts", "r");
   }
   if (mtab == NULL) {
     userlog(LOG_ERR, "neither /etc/mtab nor /proc/mounts can be read");
-    return false;
+    return NULL;
   }
 
+  array* mounts = array_create(20);
+  CHECK_NULL(mounts, NULL);
+
   char* line;
   while ((line = read_line(mtab)) != NULL) {
     userlog(LOG_DEBUG, "mtab: %s", line);
@@ -354,16 +377,16 @@ static bool unwatchable_mounts(array* mounts) {
 
     if (dev == NULL || point == NULL || fs == NULL) {
       userlog(LOG_ERR, "can't parse mount line");
-      return false;
+      return NULL;
     }
 
     if (!is_watchable(dev, point, fs)) {
-      CHECK_NULL(array_push(mounts, strdup(point)), false);
+      CHECK_NULL(array_push(mounts, strdup(point)), NULL);
     }
   }
 
   fclose(mtab);
-  return true;
+  return mounts;
 }