Running u9fs on macOS
I use the following technique to run u9fs on macOS. I’m currently running this on macOS 14 (Sonoma), but I believe I’ve used the same technique on several prior versions.
My primary use of this is to serve a root file system to Plan 9 running under qemu. I have it perform real Plan 9 authentication against my auth server.
Creating needed files
The u9fs binary
You’ll need a u9fs binary, of course.
I use the tree from https://github.com/unofficial-mirror/u9fs.
It should work as-is.
There’s a good argument for just deleting authrhosts.c
and removing it from authmethods in u9fs.c at this point,
but I haven’t done that.
Put the resulting binary somewhere stable.
The launchd file
In /Library/LaunchDaemons I create a file 9pfs.plist containing the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.p9f.u9fs</string>
<key>Program</key>
<string>/Users/a/bin/MacOSX/arm64/u9fs</string>
<key>ProgramArguments</key>
<array>
<string>u9fs</string>
<string>-l</string>
<string>/var/log/u9fs.log</string>
<string>-a</string>
<string>p9any</string>
<string>/opt/plan9</string>
</array>
<key>Sockets</key>
<dict>
<key>Listeners</key>
<dict>
<key>SockServiceName</key>
<string>9pfs</string>
</dict>
</dict>
<key>inetdCompatibility</key>
<dict>
<key>Wait</key>
<false/>
</dict>
</dict>
</plist>
A few things you’ll want to adjust:
- Make the
stringafter theProgramkey reflect wherever you have the u9fs binary installed - Confirm you’re happy with the log file location
- Confirm the tree you want to serve (
/opt/plan9in the example above)
Permissions on this file matter to launchd.
I’m not sure exactly what the criteria are, but mine is
mode 644 and owned by root:wheel, and everything is happy.
The key file
If you’re doing real Plan 9 authentication, create a file /etc/u9fs.key.
Note: this file will contain a sensitive key, so be cautious with permissions.
Mine is mode 640 and owned by root:wheel.
It should not be world-readable.
This file contains exactly three lines. They are, in order:
- auth password
- auth user
- auth domain
The conventional way to do this is to put your Plan 9 hostowner info in there,
but I don’t like sticking that in additional places.
I create a new user, unixroot, and use that.
So my file looks like:
YourSuperSecretPassword
unixroot
9srv.net
That user must exist on the auth server;
see auth/changeuser in auth(8).
The user doesn’t need to exist on the mac.
Optional: symlink /usr → /Users
If you’re using this to serve Plan 9 qemu images like I am,
it’s very useful to create a symlink from usr in the root of your tree
to your real /Users directory.
This way your qemu images will get your real home directory.
Running the results
I’m not 100% clear on when launchd re-reads its config information,
but I did the below, as root, to get it listening after setting things up like above.
:; cd /Library/LaunchDaemons
:; launchctl load org.p9f.u9fs
:; launchctl start org.p9f.u9fs
You should then see one instance returned if you run
launchctl list | grep u9fs,
plus one instance with the name followed by a UUID for each active connection.
This should get picked up on subsequent reboots without your intervention.