Repository: zargony/fuse-rs (language: rust)

Issue:
Linux umount() is only permitted for root
After commits ef283a7c8980657a388f162bc65895ba429db0d6 and e9560fda914ec9840409b2db973b7dfcf2f3eae8, Linux builds are no longer using the FUSE unmount library call, only the umount syscall.  However, this only works for root, and other users get EPERM.

The FUSE library handles this failure by running `fusermount`, which is setuid-root, just like it does for mounting in the first place.

Thus non-root users can't use drop or variable scopes to unmount a session from spawn_mount anymore.



Discussion / hints:
Ouch, I wasn't aware of that. So that's a good reason to still use `fuse_unmount_compat22` on Linux I guess


Fix patch:
diff --git a/src/channel.rs b/src/channel.rs
index fb05b19..872c451 100644
--- a/src/channel.rs
+++ b/src/channel.rs
@@ -157,10 +157,25 @@ pub fn unmount (mountpoint: &Path) -> io::Result<()> {
     // no indication of the error available to the caller. So we call unmount
     // directly, which is what osxfuse does anyway, since we already converted
     // to the real path when we first mounted.
+
     #[cfg(target_os = "macos")] #[inline]
     fn libc_umount (mnt: &CStr) -> c_int { unsafe { libc::unmount(mnt.as_ptr(), 0) } }
+
     #[cfg(not(target_os = "macos"))] #[inline]
-    fn libc_umount (mnt: &CStr) -> c_int { unsafe { libc::umount(mnt.as_ptr()) } }
+    fn libc_umount (mnt: &CStr) -> c_int {
+        use fuse::fuse_unmount_compat22;
+        use std::io::ErrorKind::PermissionDenied;
+
+        let rc = unsafe { libc::umount(mnt.as_ptr()) };
+        if rc < 0 && io::Error::last_os_error().kind() == PermissionDenied {
+            // Linux always returns EPERM for non-root users.  We have to let the
+            // library go through the setuid-root "fusermount -u" to unmount.
+            unsafe { fuse_unmount_compat22(mnt.as_ptr()); }
+            0
+        } else {
+            rc
+        }
+    }
 
     let mnt = try!(mountpoint.as_os_str().to_cstring().ok_or(
             io::Error::new(io::ErrorKind::InvalidInput, "invalid path")));


Test patch: