From: Richard Kettlewell Date: Sun, 6 Jun 2010 17:32:06 +0000 (+0100) Subject: Automatically rescan when a filesystem is mounted or unmounted. X-Git-Tag: branchpoint-5.1~77^2~12 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/commitdiff_plain/18f94073fa55c7d32d0e84ee0d8d033a950a77b0 Automatically rescan when a filesystem is mounted or unmounted. So far only tested on OS X. --- diff --git a/configure.ac b/configure.ac index b0290c9..d549db5 100644 --- a/configure.ac +++ b/configure.ac @@ -547,6 +547,18 @@ AC_C_BIGENDIAN AC_CHECK_TYPES([struct sockaddr_in6],,,[AC_INCLUDES_DEFAULT #include ]) +# 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 # had better be version 3 or later diff --git a/server/Makefile.am b/server/Makefile.am index fc7e1d9..7d59a76 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -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) \ diff --git a/server/disorder-server.h b/server/disorder-server.h index e8f4dab..5bf8916 100644 --- a/server/disorder-server.h +++ b/server/disorder-server.h @@ -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 */ /* diff --git a/server/disorderd.c b/server/disorderd.c index 14b459f..2000a2f 100644 --- a/server/disorderd.c +++ b/server/disorderd.c @@ -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 index 0000000..8a7752a --- /dev/null +++ b/server/mount.c @@ -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 . + */ +/** @file server/mount.c + * @brief Periodically check for devices being mounted and unmounted + */ +#include "disorder-server.h" +#if HAVE_GETFSSTAT +# include +# include +# include +#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: +*/