I've found that the FUSE userspace library and kernel interface has been ported, since its inception on Linux, to many other systems, and presents a relatively stable API with a supposedly small surface area. If I wanted to author a filesystem in userspace, and I were not on Plan 9 or Hurd, I would think that FUSE is my best choice.
However, I am not going to use libfuse. This is partially because of pragmatism; using C is hard in my language of choice (Monte). It's also because I am totally uninterested in writing C support code, and libfuse's recommended usage is incompatible with Monte philosophy. This shouldn't be a problem, since C is not magical and /dev/fuse can be opened with standard system calls.
Going to look for documentation, however, I've found none. There is no documentation that I can find for the /dev/fuse ABI/API, and no stories of others taking this same non-C-bound route. Frustrating.
Does any kind of documentation exist on how to interact in a language-agnostic way with /dev/fuse and the FUSE subsystem of the kernel? If so, could you point me to it? Thanks!
Update: There exists go-fuse, which is in Go, a slightly more readable language than C. However, it does not contain any ABI/API documentation either.
Update: I notice that people have voted to close this. Don't worry, there is no need for that. I have satisfied myself that the documentation that I desire does not yet exist. I will write the documentation myself, publish it, and then link to it in an accepted answer. Hopefully the next person to search for this documentation will not be disappointed.
(I'm not accepting this until it's complete. In the interim, edits are welcome!)
The basic outline of a FUSE session:
open()
is called on /dev/fuse
. I'll call the resulting FD the control FD.mount()
is called with the target mount point, filesystem type "fuse" for normal mode or "fuseblk" for block-device mode, and options including "fd=X" where X is the control FD.read()
s filesystem commands from the control FD and then write()
s responses back.umount()
is called with the target mount point.close()
is called on the control FD.With that all said, there's a handful of complications that one should be aware of. First, mount()
is almost always a privileged syscall, so you'll have to be root to mount a FUSE filesystem. However, as one may have noticed, FUSE programs can generally be started as non-root! How?
There's a helper, /bin/fusermount
, installed setuid. Usage is totally undocumented, but that's what I'm here for. Instead of open()
ing /dev/fuse
yourself, run fusermount
as a subprocess, passing the target mount point as an argument, any extra mount options you like with -o
, and (crucially) with the environment variable _FUSE_COMMFD
exported and set to the ASCII string of an open FD, which I'll call the comm FD. You must create the comm FD yourself using e.g. pipe()
. fusermount
will call open()
and mount()
for you, and share the control FD back to you along the comm FD, using the sendmsg()
trick for sharing FDs. Use recvmsg()
to read it back.
Editorial: I really don't understand why this is structured to be so difficult. FDs are inherited by subprocesses; it would have been so much easier to open()
the control FD in the top process and pass it down into fusermount
. True, there's some confused deputy dangers, but fusermount
is already installed and setuid and dangerous.
Anyway! fusermount
will crudely daemonize and take care of calling umount()
and close()
to clean up once your main process exits.
Things not yet covered:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With