ref: 3e3275363ba0db7377ad1de228a6886bbf292606
dir: /namespace-lifting.md/
# Namespace lifting The usual model for using Plan 9 namespaces is to have a single leader process construct a namespace by mounting resources that are 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 if they can't find those, rather than trying to bring in the missing pieces themselves. A good example of this is the root namespace constructed by the boot process that mounts a network stack on /net. This then gets inherited by descendant namespaces and is expected to be available by all network programs. The graphical user environment follows a similar model. When a user logs in, a new namespace is forked from the root namespace and user's profile script is run by a shell running inside this namespace. A 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. After constructing the namespace rio is run in it as the last thing. Subsequently, new windows created by rio inherit a copy of its namespace. Forking this template namespace is the only namespace operation supported by rio. In particular, rio itself doesn't provide a way to modify its namespace. This can still be achieved by an unwieldy mechanism provided by a plumber's "Local" rule. The Local rule provides a command backdoor into the originating 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) system management workflows. With pin we can "pin" a fully capable interactive shell running in the same namespace as rio, which can provide a more convenient way to interact with it. The way to do this follows. You'll have to grab and install 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 Create a conveniently named pinned rc session right before starting rio, perhaps in your profile: [plumber, upas/fs, etc.] pin -n rio0 rio The -n flag prevents pin from automatically attaching to the session, otherwise the I/O on the pinned shell would bleed into rio's GUI. Now that the rio is running we can create a window and attach to the shell just created. For lack of a better name we'll call this shell a control shell: pin rio0 To show that we can modify rio's namespace from this shell let's bind something and observe what happens. In the same pin window run: bind /sys/src /n/src Then, 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 us 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 contexts. An example that comes to mind is providing access to a namespace that is being exported over the network. Let's start by exporting an empty mountpoint, which we'll later populate using namespace ops from our namespace 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 -n 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 exportctl bind /usr /n/export Go back to the client machine and run the `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.