/\___/\
   /       \
  l  u   u  l
--l----*----l--      _   _ _                      _           _             
   \   w   /        | |_(_) |_ ____ __  __ _ _ _ ( )___  _ __| |__ _ __ ___ 
     ======         | / / |  _|_ / '  \/ _` | ' \|/(_-< | '_ \ / _` / _/ -_)
   /       \ __     |_\_\_|\__/__|_|_|_\__,_|_||_| /__/ | .__/_\__,_\__\___|
   l        l\ \                                        |_|                 
   l        l/ /
   l  l l   l /
   \ ml lm /_/
	
kitzman's place

/mnt/term on UNIX, and other hacks

plan9 linux unix 9p fuse

Introduction

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].

References

[1] https://shithub.us/kitzman/scripts/HEAD/info.html