Sunday, November 13, 2011

Getting fuse4x installed on OSX Lion

I tried out Fuse4x and sshfs for OSX, through Hombrew, this week-end. It should have been a piece of cake, but apparently the recipes aren't very good about telling when another fuse package is installed.

As recommended, I did the install:
$ brew install fuse4x sshfs

Homebrew cheerfully informs me that sshfs won't work unless I sudo copy a file, so I follow its instructions. Seems a bit strange to have to do this manually:
$ sudo cp -rfX /usr/local/Cellar/fuse4x-kext/0.8.13/Library/Extensions/fuse4x.kext /System/Library/Extensions

$ sudo chmod +s /System/Library/Extensions/fuse4x.kext/Support/load_fuse4x

Alas, things just didn't work:
$ sshfs  ~/mnt/
/Library/Filesystems/fusefs.fs/Support/fusefs.kext failed to load - (libkern/kext) link error; check the system/kernel logs for errors or try kextutil(8).
the MacFUSE file system is not available (71)

Well, actually, it looks like the kernel extension never even loaded.  OSX is supposed to attempt to auto-load them when a fuse filesystem is mounted, but it doesn't look like it succeeded. I use kextunload and kextload to get it to load the extensions:
$ kextunload /System/Library/Extensions/fuse4x.kext/

(kernel) Kext org.fuse4x.kext.fuse4x not found for unload request.
Failed to unload org.fuse4x.kext.fuse4x - (libkern/kext) not found.

$ kextload /System/Library/Extensions/fuse4x.kext/
Yet trying sshfs again gives the same error. What gives?

I look for more info on homebrew and fuse4x forums and bug lists. Wading through Web pages -- they all describing the solution to the link error as (to sum up) "use fuse4x".  I *am* using fuse4x. One bug report on homebrew hinted at a possible cause to the problem.

It looks like at some point, I had a MacFuse installed,  and it left an orphaned copy of /usr/local/lib/pkgconfig/fuse.pc:
$ cat /usr/local/lib/pkgconfig/fuse.pc

Name: fuse
Description: File System in User Space (MacFUSE)
Version: 2.7.3
Libs: -L${libdir} -lfuse -pthread  -liconv
Cflags: -I${includedir}/fuse -D__FreeBSD__=10 -D_FILE_OFFSET_BITS=64

So I brew uninstall fuse4x, remove the fuse.pc file, and brew install fuse4x.
The homebrew recipe symlinked to the correct fuse.pc file, and I hoped all was good.

It was not good. Same error.  I check the system kernel error logs:
 kernel[0]: fuse4x: starting (version 0.8.13, Nov 11 2011, 17:54:24)
 kernel[0]: kxld[]: The following symbols are unresolved for this kext:
 kernel[0]: kxld[]: _OSRuntimeFinalizeCPP
 kernel[0]: kxld[]: _OSRuntimeInitializeCPP
 kernel[0]: Can't load kext - link failed.
 kernel[0]: Failed to load executable for kext
 kernel[0]: Kext failed to load (0xdc008016).
 kernel[0]: Failed to load kext (error 0xdc008016).

Egads! Unresolved symbols? Something just isn't right.  Looks like the same 32 bit MacFuse garbage.

At this point, I'm seriously doubting the sanity of the the homebrew fuse4x/sshfs recipes. Maybe someone thought they were working, as a coincidence of them already having a working fuse4x kernel extension installed.

Well, it turns out that the MacFuse code was not fully uninstalled, and the brew recipe simply accepts the existing files without complaint or comment:
$ ls -ld /Library/Filesystems/fusefs.fs
drwxr-xr-x  4 root  wheel  136 Dec 19  2008 /Library/Filesystems/fusefs.fs

December of 2008 ???!  That's a little dated for a filesystem I installed today (Nov 2011). Even if it were unzipped from a file (which it wasn't), the datestamps of an active project should be more recent than 2008.

My experience with the fuse4x recipe is that it doesn't do squat for detecting previously installed files.... it just accepts them without complaint.

If you've got a previous install of anything remotely resembling MacFuse, clear it out, clean it out, and purge every remnant from your system before monkeying around with fuse4x.

$ /Library/Filesystems/fusefs.fs/Support/

MacFUSE Uninstaller: Sudoing...
MacFUSE Uninstaller: Can not find the for MacFUSE Core package.

Alas, if you upgraded to OSX Lion and MacFuse was previously installed, a LOT of garbage was left around. Kind of makes you wonder, why Apple still has no package management system, but I digress...
$ brew uninstall fuse4x
$ brew uninstall sshfs
$ rm -rf  /usr/local/include/fuse
$ rm /usr/local/lib/libfuse_*
$ sudo rm -rf /Library/Filesystems/fusefs.fs
$ sudo rm -rf /System/Library/Extensions/fuse4x.kext/
Hopefully, I'm not clobbering anything too important that actually worked before now.  I check for anything else fuse related: 
$ find / -name "*fuse*" -print
AHA! That explains where my MacFuse install came from! It was a stowaway on a tool I had used to support a client project!  Well, expandrive can be trashed with CleanApp. I plug the receipts as well:
$ sudo rm /private/var/db/receipts/
$ sudo rm /private/var/db/receipts/
$ sudo rm /private/var/db/receipts/
$ sudo rm /private/var/db/receipts/
OK. Time to start over. 
$ brew install fuse4x
==> Cloning
Updating /Users/myname/Library/Caches/Homebrew/fuse4x--git
==> Checking out tag fuse4x_0_8_13
==> autoreconf --force --install
==> ./configure --disable-debug --disable-static --prefix=/usr/local/Cellar/fuse4x/0.8.13
==> make install
/usr/local/Cellar/fuse4x/0.8.13: 16 files, 728K, built in 35 seconds
$ brew install sshfs
==> Cloning
Updating /Users/myname/Library/Caches/Homebrew/sshfs--git
==> Checking out tag sshfs_2_3_0
==> autoreconf --force --install
==> ./configure --disable-debug --prefix=/usr/local/Cellar/sshfs/2.3.0
==> make install
==> Caveats
Make sure to follow the directions given by `brew info fuse4x-kext`before trying to use a FUSE-based filesystem.
==> Summary
/usr/local/Cellar/sshfs/2.3.0: 6 files, 116K, built in 10 seconds
$ brew info fuse4x-kext
fuse4x-kext 0.8.13
/usr/local/Cellar/fuse4x-kext/0.8.13 (5 files, 304K)

In order for FUSE-based filesystems to work, the fuse4x kernel extension
must be installed by the root user:
  sudo cp -rfX /usr/local/Cellar/fuse4x-kext/0.8.13/Library/Extensions/fuse4x.kext /System/Library/Extensions
  sudo chmod +s /System/Library/Extensions/fuse4x.kext/Support/load_fuse4x

$ sudo cp -rfX /usr/local/Cellar/fuse4x-kext/0.8.13/Library/Extensions/fuse4x.kext /System/Library/Extensions

$ sudo chmod +s /System/Library/Extensions/fuse4x.kext/Support/load_fuse4x

$ sshfs  ~/mnt/

Finally! Everything just worked! Satisfaction!


Anatol Pomozov said...

>> Homebrew cheerfully informs me that sshfs won't work unless I sudo copy a file, so I follow its instructions. Seems a bit strange to have to do this manually:

Remember that you run Homebrew as a regular user. But kext should be owned by root - if the kext files are not owned by root then MacOSX does not let to load it. Thus when you copy as root - you change ownership.

Although I agree that Homebrew should warn if macfuse is installed. I suggest to file a bug to Homebrew, or if you are know ruby good enough - just fix it and file the patch.

Unknown said...

Anatol, thanks for the comments.

In retrospect, it should be the responsibility of the fuse4x make install action to get it right. The makefile is assuming it owns some of the same files as MacFUSE, so it would have failed just as well without brew. The Ruby recipe could mask the bug for brew users, but it would still be there in the install process.

Unknown said...

Update: Here is Anatol's suggested procedure for fixing fuse4x anomalies when macfuse botches things up. To sum up:

brew uninstall sshfs
brew link fuse4x
brew install sshfs

Kindaian said...

If you get a "Failed to unload" message, it may be natural. IF IT WASN'T LOADED.

To check it, try the last command on the brew info fuse4x-kext:

sudo kextunload -b org.fuse4x.kext.fuse4x

[ you get the error message ]

sudo kextload -b org.fuse4x.kext.fuse4x

[ no output ]

sudo kextunload -b org.fuse4x.kext.fuse4x

[ no output, and yes, no error ]

It would be nice if kextunload / kextload where a bit more verbose regarding on what is going on.

Kindaian said...

The "Failed to unload org.fuse4x.kext.fuse4x - (libkern/kext) not found." message may be because the module was not loaded in the first place.

Try to "load" it instead of unload, and try again. The message should disappear.