chiark / gitweb /
Automatically rescan when a filesystem is mounted or unmounted.
authorRichard Kettlewell <richard@kakajou.wlan.anjou.terraraq.org.uk>
Sun, 6 Jun 2010 17:32:06 +0000 (18:32 +0100)
committerRichard Kettlewell <richard@kakajou.wlan.anjou.terraraq.org.uk>
Sun, 6 Jun 2010 17:32:06 +0000 (18:32 +0100)
So far only tested on OS X.

configure.ac
server/Makefile.am
server/disorder-server.h
server/disorderd.c
server/mount.c [new file with mode: 0644]

index b0290c9..d549db5 100644 (file)
@@ -547,6 +547,18 @@ AC_C_BIGENDIAN
 AC_CHECK_TYPES([struct sockaddr_in6],,,[AC_INCLUDES_DEFAULT
 #include <netinet/in.h>])
 
+# Figure out how we'll check for devices being mounted and unmounted
+AC_CACHE_CHECK([for list of mounted filesystems],[rjk_cv_mtab],[
+  if test -e /etc/mtab; then
+    rjk_cv_mtab=/etc/mtab
+  else
+    rjk_cv_mtab=none
+  fi
+])
+if test $rjk_cv_mtab != none; then
+  AC_DEFINE_UNQUOTED([PATH_MTAB],["$rjk_cv_mtab"],[path to file containing mount list])
+fi
+
 # enable -Werror when we check for certain characteristics:
 
 old_CFLAGS="${CFLAGS}"
@@ -639,7 +651,7 @@ if test ! -z "$missing_functions"; then
 fi
 
 # Functions we can take or leave
-AC_CHECK_FUNCS([fls])
+AC_CHECK_FUNCS([fls getfsstat])
 
 if test $want_server = yes; then
   # <db.h> had better be version 3 or later
index fc7e1d9..7d59a76 100644 (file)
@@ -25,7 +25,7 @@ AM_CPPFLAGS=-I${top_srcdir}/lib -I../lib
 
 disorderd_SOURCES=disorderd.c api.c api-server.c daemonize.c play.c    \
        server.c server-queue.c queue-ops.c state.c plugin.c            \
-       schedule.c dbparams.c background.c \
+       schedule.c dbparams.c background.c mount.c \
        exports.c ../lib/memgc.c disorder-server.h
 disorderd_LDADD=$(LIBOBJS) ../lib/libdisorder.a \
        $(LIBPCRE) $(LIBDB) $(LIBAO) $(LIBGC) $(LIBGCRYPT) $(LIBICONV) \
index e8f4dab..5bf8916 100644 (file)
@@ -372,6 +372,18 @@ int play_background(ev_source *ev,
 #define START_HARDFAIL 1   /**< @brief Track is broken. */
 #define START_SOFTFAIL 2   /**< @brief Track OK, system (temporarily?) broken */
 
+void periodic_mount_check(ev_source *ev_);
+
+#ifndef MOUNT_CHECK_INTERVAL
+# ifdef PATH_MTAB
+// statting a file is really cheap so check once a second
+#  define MOUNT_CHECK_INTERVAL 1
+# else
+// hashing getfsstat() output could be more expensive so be less aggressive
+#  define MOUNT_CHECK_INTERVAL 5
+# endif
+#endif
+
 #endif /* DISORDER_SERVER_H */
 
 /*
index 14b459f..2000a2f 100644 (file)
@@ -302,6 +302,8 @@ int main(int argc, char **argv) {
   create_periodic(ev, periodic_play_check, 1, 0);
   /* Try adding a random track immediately and once every two seconds */
   create_periodic(ev, periodic_add_random, 2, 1);
+  /* Issue a rescan when devices are mounted or unmouted */
+  create_periodic(ev, periodic_mount_check, MOUNT_CHECK_INTERVAL, 1);
   /* enter the event loop */
   n = ev_run(ev);
   /* if we exit the event loop, something must have gone wrong */
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:
+*/