/mnt/term on UNIX, and other hacks
plan9 linux unix 9p fuseIntroduction
UNIX-like operating systems today already have solutions for file-sharing across machines, and remotely mounting filesystems. The easiest, and a pretty solid way, if a shared network filesystem does not exist, is to use sftp via FUSE. Even on Plan9, mounting a remote UNIX machine’s filesystem can be done through sshfs(4).
On Plan9, when rcpu-ing to remote systems, the script exports the
whole client tree, which is then mounted on /mnt/term
. That is,
whenever one connects to a cpu server, they can use the client
filesystem (including /dev
devices, local servers, etc) on
the remote machine.
So how do you get a /mnt/term
on a remote machine, if said machine
is running Linux or a BSD?
Sharing resources remotely
You can achieve a similar behaviour, when connecting to a UNIX machine, from a Plan9 one, by using ssh(1), and plan9port on the remote one.
Plan9port uses sockets to export and mount 9p filesystems, unlike the
#s
device. So, if you can set up a pipe, you can mount it remotely.
That is, you can ssh into the system, running socat instead of a shell,
and listen on a pipe. On the host machine, you would then redirect
all I/O to an export program, which in Plan9’s case, would be
exportfs(4).
Hubfs is a server which creates pipes, buffered or unbuffered, mostly for having shells attached to it. All three file descriptors would point to three pipes in a hub. That way, the shell persists and you can attach yourself to it when you reconnect. One feature is to have the files unbuffered, so the data is not persisted.
Now we know how to pipe the output between the export program, and the ssh connection.
Below is an example when the client is running Plan9. You can adapt it if you’re using Linux (i.e use u9fs, sh, etc).
#!/bin/rc
rfork n
uhost=$1
if(~ $#uhost 0) {
echo 'usage: urexport host'
exit 'usage'
}
bind '#|' /mnt/urexport
pipe0=/mnt/urexport/data
pipe1=/mnt/urexport/data1
# start exportfs
{exportfs -r / <$pipe0 >$pipe0 >[2=]} &
# start socat forwarding
{ssh $uhost .local/bin/socat \
unix-listen:srv/term - >$pipe1 <$pipe1 >[2=]} &
Mount a local server remotely
Say, we want to mount our local factotum server on a remote machine.
The created export supports mounting the servers directly:
unix% mount srv/term `{namespace}/term
unix% mount `{namespace}/term/srv/factotum `{namespace}/factotum
unix% ls `{namespace}/factotum
On Linux or BSDs, u9fs does not support mounting the pipes directly, as they are considered ‘‘special’’ files. You’d have to use socat.
Mounting a remote server locally
The plan9port servers are pipes - when mounting the remote filesystem
via sshfs, or u9fs, you won’t be able to treat the files as you
treat #s
devices.
You have to open a connection specifically for that socket.
On Plan9, you can use srv(4).
term% srv -e 'ssh '^$rhost^' socat - unix-connect:srv/news' news
term% mount /srv/news /mnt/news
Now my ported nntpfs can be used locally, on Plan9!
If your client system is Linux or BSD, you can achieve this behaviour by using socat twice:
unix% socat unix-listen:srv/news,fork,reuseaddr \
exec:'ssh $rhost socat - unix-connect:srv/news'
unix% mount srv/news `{namespace}/news
Plumb remote files
Often it is useful to use the local editor to do remote work. With the above script, you can mount your local plumber, not only a subtree of your filesystem.
Once that is done, create a script H
and set it as your $EDITOR
:
#!/usr/bin/env rc
files=()
plumber=$home/mnt/plumb/send
# Hhost=()
if(~ $#* 0) {
echo 'usage: H file' >[2=1]
exit 'usage'
}
files=($1)
shift
if(~ $#Hhost 0) {
Hhost=`{hostname}
}
# plumb file
hostfile=$files
relpath='/n/'^$"Hhost^`{pwd}
if(~ $files `{realpath $files}) {
files='/n/'^$"Hhost^$"files
}
fileslen=`{echo -n $files | wc -c}
echo 'E
edit
'^$"relpath^'
text
'^$fileslen^'
'^$"files >>$plumber
echo 'plumbed' $hostfile >[2=1]
# wait for modification
stat=`{ls -l $hostfile}
while(sleep 1) {
nstat=`{ls -l $hostfile}
if(! ~ $"nstat $"stat) {
echo $file 'modified; closing' >[2=1]
exit
}
}
Now you can plumb your remote files! This works great with commands
such as kubectl edit
. You don’t have to use a vt
anymore, nor ed
or sam -d
.
Conclusion
You can now mount your local filesystem on the remote server, use it, either from the remote host, or from other clients connecting to the machines.
The refined version of the scripts can be found in one of my repositories [1].