shithub: docs.9front.org

ref: bedac6438461449392694dd8c4a7028ccdc46019
dir: docs.9front.org/namespace-lifting.md

View raw version
# Namespace lifting

The usual model for using Plan 9 namespaces is to have a single leader
process construct a namespace out of resources known to be
needed by it or its kids.  The kids assume that their dependencies are
available at known locations and will often fail to run entirely in their
absence, rather than trying to bring in the missing pieces themselves.
An example of this is the root namespace constructed by
the boot process that mounts the network stack on `/net` and gets
inherited by descendant namespaces. All networking programs
simply expect the network resource there.

The graphical user environment follows a similar model.  When a user
logs in a new namespace is forked of the root namespace and their
profile script is run by a shell within this namespace.  The profile
script's job is to mount and bind all the resources that a
user might expect to need during a terminal session: a plumber, mail
file server, factotum, and so on.  Rio is run on top of this namespace
as the last thing.

Subsequently, windows created by rio inherit a copy of this template
namespace through forking.  Forking is the only namespace
operation directly provided by rio.
In particular, rio doesn't provide a way to modify its namespace.

This can still be achieved by an unwieldy mechanism provided by
plumber's "Local" rule.  The Local rule is a command backdoor
into rio's namespace and can be used to modify it.

I propose an alternative technique based on `pin(1)`, a pinned I/O shell.
This idea is stole...*cough* inspired! by mycroftiv's `hub(1)` workflows.

With pin we can "pin" a fully capable interactive shell running in the same
namespace as rio, providing a familiar way of interaction. The way to do
this follows.

Grab a copy of mq(4) and pin(1), both available in the same git repo:

	git/clone git://src.a-b.xyz/mq && cd mq && mk install

Pin a conveniently named rc right before starting rio, perhaps in your profile:

	[plumber, upas/fs, etc.]
	pin -c rio0
	rio

With rio running we can create a window and attach to the pinned shell.
For lack of a better name we'll call this a control shell:

	pin -a rio0

To show that we can modify rio's namespace let's bind something an
observe what happens. Run in the control shell:

	bind /sys/src /n/src

Create a new window and check that the system's source code is indeed
bound to a new name /n/src:

	ls /n/src

Careful readers will have guessed that this didn't change the namespaces
of windows that were created prior to changing rio's namespace.
Remember that rio creates (almost) identical *copies* of its namespace
for every new window, but these are in fact different entities independent
of each other.

This same trick can be applied in other situations.  An example that comes
to mind is providing access to a namespace being exported over
the network.

Let's start by exporting an empty mountpoint, which we'll later populate
using namespace operations from our control shell.

Firstly, we'll need to use srvfs(4) to create a persistent mountable
namespace which we'll mount in the network listener and export with
exportfs(4).  You might have thought that we could use exportfs(4)
directly but that way we'd be actually exporting a different namespace
for each connection.

Run

	pin -c exportctl
	srvfs export /n/export

This will create a `/srv/export` pipe "containing" our namespace.
Next we'll create a listener to export this pipe to network clients.
Exportfs with the -S flag can be used for the task:

	aux/listen1 tcp!*!999 /bin/exportfs -S /srv/export

Let's see if we can connect, run the following:

	srv tcp!your.ip.or.name!999 export /n/export

This should mount our directory to /n/export on the client side. Run
`ls /n/export` and assert that it's empty.

Now let's change the exported namespace using our `exportctl` pin
on the server machine.

	pin -a exportctl
	bind /usr /n/export

Go back to the client machine and run `ls /n/export` again, this time
user directories should show up.

That's it folks. I'd like to hear if you find some other tricks to do with this.