chiark / gitweb /
Automatically rescan when a filesystem is mounted or unmounted.
[disorder] / server / mount.c
diff --git a/server/mount.c b/server/mount.c
new file mode 100644 (file)
index 0000000..8a7752a
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * This file is part of DisOrder.
+ * Copyright (C) 2010 Richard Kettlewell
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/** @file server/mount.c
+ * @brief Periodically check for devices being mounted and unmounted
+ */
+#include "disorder-server.h"
+#if HAVE_GETFSSTAT
+# include <sys/param.h>
+# include <sys/ucred.h>
+# include <sys/mount.h>
+#endif
+
+#if HAVE_GETFSSTAT
+static int compare_fsstat(const void *av, const void *bv) {
+  const struct statfs *a = av, *b = bv;
+  int c;
+  c = memcmp(&a->f_fsid, &b->f_fsid, sizeof a->f_fsid);
+  if(c)
+    return c;
+  c = strcmp(a->f_mntonname, b->f_mntonname);
+  if(c)
+    return c;
+  return 0;
+}
+#endif
+
+void periodic_mount_check(ev_source *ev_) {
+#if HAVE_GETFSSTAT
+  /* On OS X, we keep track of the hash of the kernel's mounted
+   * filesystem list */
+  static int first = 1;
+  static unsigned char last[20];
+  unsigned char *current;
+  int nfilesystems, space;
+  struct statfs *buf;
+  gcrypt_hash_handle h;
+  gcry_error_t e;
+
+  space = getfsstat(NULL, 0, MNT_NOWAIT);
+  buf = xcalloc(space, sizeof *buf);
+  nfilesystems = getfsstat(buf, space * sizeof *buf, MNT_NOWAIT);
+  if(nfilesystems > space)
+    // The array grew between check and use!  We just give up and try later.
+    return;
+  // Put into order so we get a bit of consistency
+  qsort(buf, nfilesystems, sizeof *buf, compare_fsstat);
+  if((e = gcry_md_open(&h, GCRY_MD_SHA1, 0))) {
+    disorder_error(0, "gcry_md_open: %s", gcry_strerror(e));
+    return;
+  }
+  for(int n = 0; n < nfilesystems; ++n) {
+    gcry_md_write(h, &buf[n].f_fsid, sizeof buf[n].f_fsid);
+    gcry_md_write(h, buf[n].f_mntonname, 1 + strlen(buf[n].f_mntonname));
+  }
+  current = gcry_md_read(h, GCRY_MD_SHA1);
+  if(!first && memcmp(current, last, sizeof last))
+    trackdb_rescan(ev_, 1/*check*/, 0, 0);
+  memcpy(last, current, sizeof last);
+  first = 0;
+#elif defined PATH_MTAB
+  /* On Linux we keep track of the modification time of /etc/mtab */
+  static time_t last_mount;
+  struct stat sb;
+  
+  if(stat(PATH_MTAB, &sb) >= 0) {
+    if(last_mount != 0 && last_mount != sb.st_mtime)
+      trackdb_rescan(ev_, 1/*check*/, 0, 0);
+    last_mount = sb.st_mtime;
+  }
+#endif
+}
+
+/*
+Local Variables:
+c-basic-offset:2
+comment-column:40
+fill-column:79
+indent-tabs-mode:nil
+End:
+*/