about summary refs log tree commit homepage
path: root/mnt_usable.c
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-02-08 08:48:36 +0000
committerEric Wong <normalperson@yhbt.net>2013-02-08 08:48:36 +0000
commite427fb773837953c01ebe8dfaf8f8679c7895fc2 (patch)
tree5008c15a3a2ebf8e7fee043ae9880a8a7cd7568c /mnt_usable.c
parent223adf17682765f9e72d3436348700085d823a6e (diff)
downloadcmogstored-e427fb773837953c01ebe8dfaf8f8679c7895fc2.tar.gz
This centralizes the mountpoint suitability logic in
one place.  In the future, it may also allow us to
parallelize the work of scanning filesystems.
Diffstat (limited to 'mnt_usable.c')
-rw-r--r--mnt_usable.c44
1 files changed, 42 insertions, 2 deletions
diff --git a/mnt_usable.c b/mnt_usable.c
index 1d590b1..9ba52e4 100644
--- a/mnt_usable.c
+++ b/mnt_usable.c
@@ -16,18 +16,58 @@
 #define MY_STATFS statvfs
 #endif
 
+static bool resolve_symlink(char **orig)
+{
+        char *p = canonicalize_filename_mode(*orig, CAN_EXISTING);
+
+        if (p) {
+                free(*orig);
+                *orig = p;
+                return true;
+        }
+        return false;
+}
+
+static bool stat_harder(struct mount_entry *me)
+{
+        struct stat sb;
+
+        /* the device number may not have been populated, do it */
+        if (me->me_dev == (dev_t)-1) {
+                if (stat(me->me_mountdir, &sb) != 0)
+                        return false;
+                me->me_dev = sb.st_dev;
+        }
+
+        /*
+         * resolve symlinks for things that look like paths
+         * and skip dead symlinks
+         */
+        if (me->me_devname[0] == '/') {
+                if (lstat(me->me_devname, &sb) == 0
+                    && S_ISLNK(sb.st_mode)
+                    && ! resolve_symlink(&me->me_devname))
+                        return false;
+        }
+        return true;
+}
+
 /*
  * prevents us from using filesystems of unknown size, since those could
  * be stalled/dead network mounts
  */
-bool mog_mnt_usable(const char *path)
+bool mog_mnt_usable(struct mount_entry *me)
 {
         struct MY_STATFS buf;
+        const char *path = me->me_mountdir;
+
+        if (me->me_dummy)
+                return false;
 
 retry:
         errno = 0;
         if (MY_STATFS(path, &buf) == 0)
-                return (buf.f_blocks > 0);
+                return (buf.f_blocks > 0) ? stat_harder(me) : false;
 
         /* unknown */
         assert(errno != EFAULT && "BUG: EFAULT from statfs/statvfs");