shithub: 9intro

ref: 2b99422480d596ebc26921c87c6bb81a07949f3e
dir: 9intro/ch7.ms

View raw version
.so tmacs
.BC 7 "Resources and Names
.BS 2 "Resource fork
.LP
.ix "resource sharing
.ix "file name
.ix "resource fork
In chapter 4 we used
.CW fork
.ix [fork]
.ix "process creation
to create new processes. We said that
.CW fork
was a system call. We lied. It is not a venial lie, like when saying
that
.CW getenv
.ix [getenv]
is a system call (because it is a library function). It is a terrible lie,
because Plan 9 processes are not just clones.  Now it is time to tell the truth.
.PP
A Plan 9 process is mostly what you imagine because of what we have said
so far. It is a flow of control known by the kernel, which creates the illusion
of having a dedicated processor to run it. Each process has certain resources
that are abstractions provided by Plan 9 to let it perform its job. We have
seen many of such resources: Memory, environment variables, file descriptors, and
.ix "process resource"
.ix "environment variable
.ix "environment process group
.ix "file descriptor process group
.ix "note process group
note groups.
.PP
When we discussed
.CW fork ,
we said that a child process is a
.I copy
of the parent process. Therefore, it seemed that all resources for the
parent were copied to build a (child) clone. 
Because
.CW fork
is so hard to understand the first time you use it, we decided to lie.
.PP
But
the truth is that to create a Plan 9 process you do not have to copy all the
resources from the parent process. You may specify which resources are
to be copied, which ones are to be
.ix "parent process
.ix "child process
.I shared
with the parent, and which ones are to be brand
.I new
(and empty) just for the child.
.PP
The system call doing this is
.CW rfork ,
and
.CW fork
is equivalent to a call to
.CW rfork
.ix [rfork]
asking for a copy of the parent's file descriptor table, a new flow of control,
and a copy of the parent's memory. On the other hand,
environment variables, and the note
group are shared with the parent.
.PP
This is the complete list of resources for a process, which can be controlled using
.CW rfork :
.IP •
The \fBflow of control\fP
.ix "control flow" .
There is not much we can do about it, but to ask for new one.
Each one is called a
.I process .
.IP •
The
.B "file descriptor table" .
Also known as the file descriptor group. You can ask for a copy, or
for sharing with the child when creating a process, or for a new table with
all descriptors closed.
.IP •
.B "Environment variables" .
Also known as the environment group. Like before, You can ask for a copy, or
for sharing with the child when creating a process, or for a new set of
environment variables with no variable defined on it.
.IP •
The
.B "name space" .
Utterly important, and central to Plan 9. We have been ignoring this until
now. This is the resource that maps file names to files. We study it in this
chapter.
.IP •
The
.B "working directory
and the
.B "root directory" ,
.ix slash
used to walk the file tree for relative and absolute paths.
.ix path
.ix "file tree
.IP •
The \fBmemory segments\fP.
.ix "virtual memory segment
You can ask for sharing the data with the child, when creating a process,
or to make a copy for the child. The text, or code,  is always shared. It is
read-only, and it would be a waste to copy memory that is going to remain
the same. The stack is
.I never
shared, because each process has its own flow of control and needs its
own stack.
.IP •
The
.B "note group" .
You can ask for sharing it with the child, when creating a process, or to
obtain your own group to be isolated from others.
.IP •
The
.B "rendezvous group" .
.ix [rendezvous]
A resource used to make groups of processes that can use the
.CW rendezvous
system call to coordinate among them. This is yet to be seen.
.LP
Besides the requests mentioned above, there are several other things
that
.CW rfork
can do, that we will be seeing in this chapter along with them.
.PP
Before proceeding, we are going to do a
.CW fork ,
but in a slightly different way:
.so progs/rforkls.c.ms
.ix [rforkls.c]
.LP
This program is like the one we saw,
.CW runls ,
which did run
.CW ls
in a child process. This time it is using the actual system call,
.CW rfork .
This call receives a set of flags, packaged into its single parameter using
a bit-or. All the flags for
.CW rfork
have names that start with “\f(CWRF\fP”.
The most important one here is
.CW RFPROC .
.ix "[RFPROC] [rfork]~flag
It asks for a new process, i.e., a new flow of control.
.ix "new process
.ix "control flow
.PP
When you do
.I not
specify
.CW RFPROC ,
the operations you request with other flags are done to your own process,
and not to the child. When you do specify it, the other flags refer to the child.
.PP
The default behavior of
.CW rfork
is to make a copy of the memory for the child, and to share most other things
with the parent. To do exactly a
.CW fork ,
we must ask for a copy of the file descriptor table including the
.CW RFFDG
.ix "file descriptor group
.ix "[RFFDG] [rfork]~flag
(RFork File Descriptor Group). But for the memory, which is duplicated
by default, other resources are shared by default. When you give the flag
for a resource to
.CW rfork ,
you are asking for a copy. When you use a slightly different flag, that has a
.CW C
in it (for “clean”), you are asking for a brand new, clean, resource.
Because of what we said, you can imagine that
.CW RFREND
.ix "[RFFDG] [rfork]~flag
.ix "rendezvous group
is asking for a another rendezvous group, but this does not really matter by now.
.PP
Running this program executes
.CW ls ,
as expected.
.P1
; 8.rforkls
rforkls.c
rforkls.8
8.rforkls
;
.P2
.LP
But let's change the call to rfork with this other one
.P1
rfork(RFCFDG|RFREND|RFPROC)
.P2
.LP
and try again
.P1
; 8.rforkls
;
.P2
.LP
.I Nothing !
.PP
The explanation is that
.CW RFCFDG
provided a
.I clean
file descriptor table (or group) to the child process. Because standard output
was not open in the child,
.CW ls
could not print its output. Furthermore, because its standard error was
closed as well, it could not even complain about it.
.PP
Now we are going to do the same, to our own process. 
.so progs/rforkhi.c.ms
.LP
This produces this output
.P1
; !!8.rforkhi
; hi
;
.P2
.LP
The second message was not shown. The
.CW RFCFDG
flag to
.CW rfork
asks for a
.I clean
file descriptor set (group). This works like in the previous program, but this time
we did not specify
.CW RFPROC
and therefore, the request was applied to our own process.
.BS 2 "Protecting from notes
.LP
The note group is shared by default when doing a
.ix "note group
.CW fork ,
because no flag is specified regarding this resource. This means that when we
run our program in a window, pressing
.I Delete
.ix [Delete]
in the window will kill our process. The window system posts an
.CW interrupt
.ix "[interrupt] note
note to the note group of the shell in the window, and our process is a child
of the shell, sharing its note group.
.PP
This may be an inconvenience. Suppose we are implementing a web server, that
is meant to be always running. This program is meant to run in the background,
because it does not need a console to read commands. The user is expected
to run our server as in
.P1
; httpd &
;
.P2
.LP
to be able to type more commands in the shell. However, if the user now hits
.I Delete
to stop another program, the web server is killed as well. This can be avoided by
.ix "[RFNOTEG] [rfork]~flag
calling
.P1
rfork(RFNOTEG);
.P2
.LP
in the program for
.CW httpd .
This puts the process in a new note group. We are no longer affected by notes
to the group of the shell that runs in our window. To try this, run this program
commenting out the call to
.CW rfork ,
and hit
.I Delete .
.so progs/noterfork.c.ms
.ix [noterfork.c]
.LP
The program gets killed.
.P1
; 8.noterfork
0 1 2 \fBDelete\fP
;
.P2
.LP
With the call in place, the program happily ignores us until it completes.
.P1
; 8.noterfork
0 1 2 \fBDelete\fP 3 4 5
;
.P2
.LP
Imagine this program is our
.CW httpd
server. If the user forgets to type the ampersand, it will block the shell forever
(it is waiting for the child to die). The only way to kill it is to open a new window and
.ix [wait]
kill manually the process by writing to its
.CW ctl
file, as we saw before. To be nicer, our program could fork a child and let
its original process die. The shell prompt would be right back. Because we still
want to protect from notes, we must get a new note group as well.
.PP
The program, shown next, produces the same output, and convinces the shell that it
should read another line immediately after we start.
.P1
; 8.noterfork
; 0 1 2 \fBDelete\fP
; 3 4 5
.P2
.LP
Because the shell is reading a command line, when we type
.I Delete ,
it understands that we want to interrupt what we typed and prints
another prompt, but our fake
.CW httpd
program is still alive. The
.CW RFNOTEG
flag applies to our child process, because we said
.CW RFPROC
as well.
.so progs/httpd.c.ms
.BS 2 "Environment in shell scripts
.LP
.ix "environment variable
.ix "shell script
.ix "resource sharing
Environment variables are shared by default. This means that if we change
any environment variable, our parent and other sibling process sharing the
environment variables will
be able to see our change.
.PP
Shell scripts are executed by a child shell process,
.ix "subshell
.ix "child process
and this applies to them as well. when you define a variable in a shell script,
the change remains in the environment variable table after the script has died.
For example, this script copies some source and documentation files to several
directories for a project. It defines the
.CW projectdir
environment variable.
.so progs/copy.ms
.ix "[copy] [rc]~script
.LP
Look what happens:
.P1
; copy
; lc /env/projectdir
projectdir
.P2
.LP
After executing
.CW copy ,
the environment variable is not yet known to our shell. The reason is that the
shell caches environment variables. Starting a new shell shows that indeed, the
variable
.CW projectdir
is in our environment. This is also seen by listing
.CW /env .
.ix [/env]
The file representing the variable is defined there.
.P1
; echo $projectdir

; rc
; echo $projectdir
/sys/src/planb
.P2
.LP
How can we avoid polluting the set of environment variables for the parent shell?
By asking in the script for our own
.I copy
of the parent process' environment. This, in a C program, would be done calling
.CW rfork(RFENVG) .
.ix "[RFENVG] [rfork]~flag
.ix "environment group
In the shell, we can run the command
.P1
rfork e
.P2
.LP
that achieves the same effect. The command is a builtin, understood and executed
.ix "[rfork] command
.ix "builtin command
by
.CW rc
itself. it is very sensible to start most scripts doing this:
.P1
#!/bin/rc
rfork ne
.I ...
.P2
.LP
This creates a copy of the environment variables table (\f(CWe\fP) and the
name space (\f(CWn\fP) for the process executing the request. Because it is a copy,
any change does not affect the parent. When the shell interpreting the script dies,
the copy is discarded.
.BS 2 "Independent children
.LP
.ix "independent child process
.ix "process termination
All the programs we have done, that create a child process and do not wait for it,
are wrong. They did not fail, but they were not too nice to Plan 9.
.PP
When a child process dies, Plan 9 must maintain its exit message until the parent
process waits for it. However, if the parent process is never going to wait for the
child, Plan 9 does not know for how long to keep the message. Sooner or later
the message will be disposed of, e.g., after the parent dies.
.PP
But if we are not going
to wait, it is best to tell Plan 9 that the child is disassociated from the parent. When the
child dies, it will leave no message because no one is going to wait for it. This is
achieved by specifying the flag
.CW RFNOWAIT
.ix "[RFNOWAIT] [rfork]~flag
.ix "dissociated child
along with
.CW RFPROC
when the new, dissociated, child is being created. For example, this is the
correct version for our
.CW child
program that used
.CW fork
to create a child process.
.P1
#include <u.h>
#include <libc.h>

void
main(int, char*[])
{
	switch(rfork(RFFDG|RFREND|RFPROC|RFNOWAIT)){
	case -1:
		sysfatal("fork failed\n");
	case 0:
		print("I am the child\n");
		break;
	default:
		print("I am the parent\n");
	}
	exits(nil);
}
.P2
.LP
The flags
.CW RFFDG|RFREND|RFPROC
are equivalent to calling
.CW fork ,
.ix [fork]
but this time we say
.CW RFNOWAIT
as well.
.BS 2 "Name spaces
.LP
.ix "name resolution
.ix "path
.ix "walk
.ix "file tree
.ix "name space
.ix "file name
In Plan 9, we use file names like
.CW /usr/nemo .
A name is just a string. It is a sequence of characters. However, because it
is a file name, we give some meaning to the string. For example, the name
.CW /usr/nemo
means:
.IP 1
Start at the file named
.CW / ,
which is also known as the root directory.
.IP 2
Walk down the file tree to the file with name
.CW usr ,
.IP 3
Walk down again to the file named
.CW nemo .
You have arrived.
.LP
This name specifies a path to walk through the tree of files to reach a
particular file of interest, as shown in figure [[!tree walk!]].
What is a file? Something that you can
.CW open ,
.CW read ,
.CW write ,
.ix [open]
etc. As long as the file implements these operations, both you and Plan 9
are happy with it.
.LS
.PS
.ps +2
circlerad=.2
movewid=.2
arrowhead=.7
.CW
down
S: circle invis "\fB/\fP"
move
L: [ right
	A: circle invis  "386"
	move
	X: circle invis "arm"
	move
	B: circle invis  "\fBusr\fP"
	move
	Y: circle invis "n"
	move
	C: circle invis  "tmp"
]
move
U: [ right
	A: circle invis  "\fBnemo\fP"
	move
	B: circle invis  "glenda"
	move
	C: circle invis  "mero"
]
line from S to L.A chop
line from S to L.B chop
line from S to L.X chop
line from S to L.Y chop
arrow from S+.005,.005 to L+.005,.005 chop
line from S to L.C chop
line from L.B to U.A chop
arrow from L.B+.005,.005 to U.A+.005,.005 chop
line from L.B to U.B chop
line from L.B to U.C chop
.R
.ps -2
reset
.PE
.LE F A file name is a path to walk in the tree of files.
.PP
.ix [/]
But how can “\f(CW/\fP”, which is just a name, refer to a file? Where does it
come from? And why can a name like
.CW /dev/cons
refer to different files at different windows? The answers come from the
abstraction used to provide names for files, the
.B "name space" .
In this case, names are for files, and we will not be saying this explicitly. It
should be clear by the context.
.PP
A name space is just a set of names that you can use (all the file paths that
you might ever use in your file tree). Somewhat confusingly, the abstraction
that provides a name space is also called a name space. To add more
confusion, this is also called a
.B "name service" .
.PP
The name space takes a name, i.e., a string, and translates this name into
something that can be used as a file in Plan 9. This translation is called
\fBresolving a name\fP.
.ix "name resolution
.ix "walk
.ix [Chan]
.ix kernel
It takes a name and yields a Chan, the data structure used to represent a file
within the Plan 9 kernel. Thus, you might say that resolving a name takes
a string and yields a file.
The translation is done by walking through
the file tree as shown above.
.PP
Because Plan 9 is a distributed system, your kernel does not have any
data structure to implement files. This may be a surprise, because in Plan 9
.I "everything is a file" ,
or at least looks like a file.
But Plan 9 does not provide the files itself. Files are provided
by other programs that may be running far away in the network, at different
machines. These programs are called \fBfile servers\fP.
.ix "file server
.ix "file tree
.PP
File servers implement and maintain file trees, and you may talk to them across the
network, to walk their trees and use their files. But you cannot even touch nor
see the files, they are kept inside a file server program, far away.
What you can do is to talk to the file server program to ask it to do whatever you
may want to do to the files it keeps.
The protocol used to talk (i.e., the language spoken) is called 9P. The section
.ix 9P
.ix "file system protocol
5 of the system manual documents this protocol. Any program speaking 9P can
be used as a file server for Plan 9.
.PP
The conversation between Plan 9 and a file server is made through a
.I "network connection" .
.ix "network connection
If you have not attended to a computer networks course, you can imagine it is
a phone call, with Plan 9 at one end, and the file server at the other. In the last
chapter we saw how to establish network connections, i.e., how to make calls.
This makes a network connection to the program we use as our file server:
.P1
.ps -1
; srv tcp!whale!9fs
post...
; ls -l /srv/tcp!whale!9fs
--rw-rw-rw- s 0 nemo nemo 0 May 23 17:44 /srv/tcp!localhost!9988
;
.ps +1
.P2
.LP
The program
.CW srv
.ix [srv]
.ix "file descriptor post
dialed the address
.CW tcp!whale!9fs
and, after establishing a connection, posted the file descriptor for the connection
at
.CW /srv/tcp!whale!9fs .
This file (descriptor) has a file server program that speaks 9P at the other end
of the connection.
.PP
However, to access files in the file server, we must be able to see those
files in our file tree, i.e., in our name space. Otherwise we would not be able
to write paths leading to such files. We can do it. The Plan 9
.CW mount
.ix [mount]
.ix "file system mount
.ix "mount table
system call modifies the name space and instructs it to
.I jump
to a new file when you reach a given file. The shell command
.CW mount
does the same.
.LS
.PS 5.3i
circlerad=.25
movewid=.2
arrowhead=.7
.CW
down
S: circle invis "\fB/\fP"
move
L: [ right
	A: circle invis  "386"
	move
	X: circle invis "arm"
	move
	B: circle invis  "usr"
	move
	C: circle invis  "tmp"
	move
	Y: circle invis  "\fBn\fP"
]
move
U: [ right
	circle invis
	move
	A: circle invis  "nemo"
	move
	B: circle invis  "glenda"
	move
	C: circle invis  "mero"
	move .5
	W: circle invis  "\fBwhale\fP"
]
line from S to L.A chop
line from S to L.B chop
line from S to L.X chop
line from S to L.Y chop
arrow from S+.005,.005 to L.Y+.005,.005 chop
line from S to L.C chop
line from L.B to U.A chop
line from L.B to U.B chop
line from L.B to U.C chop
line from L.Y to U.W chop
arrow from L.Y+.005,.005 to U.W+.005,.005 chop
move from U.W.e right 1.5
R: circle invis "\fB/\fP"
down
move
K: [ right
	A: circle invis  "386"
	move
	X: circle invis "arm"
	move
	B: circle invis  "usr"
	move
	C: circle invis  "..."
]
line from R to K.A chop
line from R to K.X chop
line from R to K.B chop
line from R to K.C chop
B1: box dashed at U.W
B2: box dashed at R
arrow dashed from B1.e to B2.w
line dashed from B1.e+0,.005 to B2.w+0,.005 "mount" above
.R
reset
.PE
.LE F The file tree reached through \f(CWtcp!whale!9fs\fP is mounted at \f(CW/n/whale\fP.
.PP
This may seem confusing at first, but it is quite simple.
.ix walk
For example, we may change our name
space so that when we walk through our file tree, and reach the directory
.CW /n/whale ,
we continue our walk,
.I not
at
.CW /n/whale ,
but at the root directory of the file server reached through
.CW /srv/tcp!whale!9fs .
For example,
.P1
; lc /n/whale
; mount -c /srv/tcp!whale!9fs /n/whale
; lc /n/whale
386		acme	cron	mnt	tmp
LICENSE		adm	dist	n	usr
LICENSE.afpl	alpha	lib	power
LICENSE.gpl	arm	lp	rc
NOTICE		cfg	mail	sys
.P2
.LP
Before executing
.CW mount ,
the directory
.CW /n/whale
was empty. After executing it, the original directory is still empty, but our
name space is instructed to jump to the root directory of file server at
.CW /srv/tcp!whale!9fs ,
whenever we reach
.CW /n/whale .
Therefore,
.CW lc
is not really listing
.CW /n/whale ,
but the root for our file server. The nice thing is that
.CW lc
is happy, because the name space keeps it unaware of where the files
might be.
Figure [[!mounted tree!]] shows how
.CW lc
walked the file tree, and makes it clear why it listed the root directory
in the file server. The dashed boxes and the arrow represent the mount we made.
.PP
The data structure that implements the name space is called the
.B "mount table" .
It is a table that maintains entries saying: Go from this file to this other file.
This is what we just saw. After calling
.CW mount
in our example, our mount table contains a new entry represented in the
figure [[!new entry in mount table!]].
The source for the translation is called the
.B "mount point" ,
the destination for the translation is called the
.B "mounted file" .
.LS
.PS
.ps -2
boxwid=1.5
boxht=.4
right
box "Chan for" "\f(CW/n/whale\fP"
arrow right 1.5
box "Chan for \f(CW/\fP" "at tcp!whale!9fs"
reset
.ps +2
.PE
.LE F New entry in mount table after mounting \f(CWtcp!whale!9fs\fP at \f(CW/n/whale\fP.
.PP
Do not get confused by the Chans. For your Plan 9 kernel, a Chan is just a file.
.ix [Chan]
It is the data structure used to speak 9P with a file server regarding a particular
file. Therefore, the figure might as well say “File for \f(CW/n/whale\fP”.
.PP
Each time the name space walks one step in the file tree to resolve a name, the
mount table is checked out to see if walking should continue at a different file,
as happen to
.CW /n/whale .
If there is no such entry, the walk continues through the file tree,  as expected.
.PP
As a convenience, the program
.CW srv
can mount a 9P file server, besides dialing its address and posting the connection file
descriptor at
.CW /srv .
The following command line dials
.CW tcp!whale!9fs ,
like before, but it also mounts that connection at
.CW /n/whale ,
like we did. The file created at
.CW /srv
is named by the second parameter.
.P1
; srv tcp!whale!9fs whale /n/whale
post...
; lc /srv/whale
whale
;
.P2
.LP
By convention, there is a script called
.CW /bin/9fs ,
.ix "[9fs] [rc]~script
that accepts as an argument the file system to mount. It is customized for
each local Plan 9 installation. Therefore, looking into it is a good way of
finding out which file servers you have around. This command achieves
the same effect of the previous command line, when used at URJC:
.P1
; 9fs whale
post...
;
.P2
.LP
We have
.I added
new files to our file tree, by mounting a remote file tree from a 9P file server
into a directory that we already had. The mechanism used was a translation
going from one file to another.
When we have two files in our file tree, the same mechanism can be applied
to translate from one to another. That is, we can ask our name space to
jump to a file
.I "already in our tree
when we reach another that we also have in the tree. A mount
for two files already in the tree is called a
.B binding .
.PP
The system call (and the shell command) used to do a bind is
.CW bind .
.ix [bind]
For example,
.P1
; bind -c /n/whale /n/other
.P2
installs a new entry in the mount table that says: When you reach
.CW /n/other ,
continue at
.CW /n/whale .
But note, the names used are interpreted using the name space! Therefore,
.CW /n/whale
is not the old (empty) directory it used to be. It now refers to the root of the
file server at whale. And so, listing
.CW /n/other
yields the list for the root directory of our file server.
.P1
; lc /n/other
386		acme	cron	mnt	tmp
LICENSE		adm	dist	n	usr
LICENSE.afpl	alpha	lib	power
LICENSE.gpl	arm	lp	rc
NOTICE		cfg	mail	sys
.P2
.LP
Because our mount table includes now the entries shown in figure [[!mount table bind!]].
.LS
.PS
.ps -2
boxwid=1.5
boxht=.4
down
[
	right
	box "Chan for" "\f(CW/n/whale\fP"
	arrow right 1.5
	box "Chan for \f(CW/\fP" "at tcp!whale!9fs"
]
move
[
	right
	box "Chan for" "\f(CW/n/other\fP"
	arrow right 1.5
	box "Chan for \f(CW/\fP" "at tcp!whale!9fs"
]

reset
.ps +2
.PE
.LE F Entries in the mount table after the bind  from \f(CW/n/other\fP to \f(CW/n/whale\fP. 
.PP
How can we know how our name space looks like? Or, how can we know
which entries are installed in our mount table? The name space is a resource,
like file descriptors, and environment variables. Each process may have its
own name space (as controlled by
.CW rfork ),
although the custom is that processes in the same window share their
name spaces.
.PP
The file
.CW ns
.ix "process [ns] file
.ix "[/proc] file system
.ix "[#p] device driver
in the directory in
.CW /proc
for a process,  lists the mount table used by that process.
Each entry is listed using a text line
similar to the command used to install the entry. To obtain the entries we have installed,
we can use
.CW grep ,
.ix [grep]
to print lines in our
.CW ns
file that contain the string
.CW whale :
.P1
; echo $pid
843
; grep whale /proc/843/ns
mount -c #s/tcp!whale!9fs /n/whale 
mount -c #s/tcp!whale!9fs /n/other 
.P2
.LP
Because lines at
.CW /proc/$pid/ns
are not yet ready for use as shell commands, there is a command called
.CW ns
(name space)
.ix [ns]
that massages them a little bit to make them prettier and ready for use.
Using
.CW ns
is also more convenient
because you do not need to type so much:
.P1
; ns | grep whale
mount -c '#s/tcp!whale!9fs' /n/whale 
mount -c '#s/tcp!whale!9fs' /n/other 
.P2
.LP
The effect of a mount (or a bind) can be undone with another system call, called
.CW unmount ,
.ix [unmount]
or using the shell command of the same name:
.P1
; unmount /n/whale
; lc /n/whale
; grep whale /proc/843/ns
mount -c #s/tcp!whale!9fs /n/other 
;
.P2
After executing
.CW unmount ,
the name space no longer jumps to the root of the file server at
.CW whale
when reaching
.CW /n/whale ,
because the entry in the mount table for
.CW /n/whale
has been removed. What would happen now to
.CW /n/other ?
.P1
; lc /n/other
386		acme	cron	mnt	tmp
LICENSE		adm	dist	n	usr
LICENSE.afpl	alpha	lib	power
LICENSE.gpl	arm	lp	rc
NOTICE		cfg	mail	sys
.P2
.LP
Nothing! It remains as before. We removed the entry for
.CW /n/whale ,
but we did not say anything regarding the bind for
.CW /n/other .
This is simple to understand if you think that your name space, i.e., your
mount table, is just a set of translations from one file to another file. Here,
.CW /n/other
leads to the file that had the name
.CW /n/whale .
This file was the root of our file server, and not the empty directory. To undo
the mount for this directory, we know what to do:
.P1
; unmount /n/other
; lc /n/other
;
.P2
.LP
In some cases, a single file server may provide more than one file tree.
For example, the file system program used in Plan 9,
.CW fossil ,
.ix [fossil]
.ix "file server program
.ix "file system snapshot
.ix "file system dump
.ix "archive
makes a snapshot of the entire file tree each day, at 5am, and archives it
for the posterity. It archives only the changes with respect to the last archive,
but provides the illusion that the whole tree was archived as it was that day.
.PP
Above, we mounted the
.I active
file tree provided by the
.CW fossil
file server running at
.CW whale .
But we can mount the archive instead. This can be done supplying an optional
argument for
.CW mount ,
.ix "attach specifier
.ix "mount specifier
that specifies the name of the file tree that you want to mount. When you do not
name a particular file tree served from the file server, its
.I main
.ix [main/active]
file tree is mounted. For fossil, the name of the main file tree is
.CW main/active .
This command mounts the archive (also known as the
.I dump )
for our main file server, and not the active file tree (i.e., that of today):
.P1
; mount /srv/tcp!whale!9fs /n/dump main/archive
; lc /n/dump
2001	2002	2003	2004	2005	2006
; ls /n/dump/2004
0101
0102
0103
0104
.I  "... and may more directories. One per day, until...
1230
1231
;
.P2
.LP
This is very useful. You may copy files you had years ago, you may compare
them to those you have today, and you may even used them! The following
commands change your
name space to use the C library you were using on May 4th, 2006:
.P1
.ps -1
; bind /n/dump/2006/0504/386/lib/libc.a /386/lib/libc.a
; bind /n/dump/2006/0504/sys/include/libc.h /sys/include/libc.h
.ps +1
.P2
.LP
Remember what
.CW bind
.ix [bind]
does. When your compiler and linker try to use
.CW libc.a ,
and
.CW libc.h ,
the name space jumps to those archived in the dump. If you suspect that
a program is failing because of a recent bug in the C library, you can check that out
by compiling your program using the library you had time ago, and running it again
to see if it works this time.
.PP
The script
.CW 9fs
.ix "[9fs] [rc]~script
also knows how to mount the dump. So, we could have said
.P1
.ps -1
; 9fs dump
; bind /n/dump/2006/0504/386/lib/libc.a /386/lib/libc.a
; bind /n/dump/2006/0504/sys/include/libc.h /sys/include/libc.h
.ps +1
.P2
.LP
instead of mounting the dump using
.CW srv
and
.CW mount .
.BS 2 "Local name space tricks
.LP
.ix "[Local]
.ix [acme]
You must always take into account that name spaces, i.e., mount tables,
are
.I per-process
in Plan 9. Most processes in the same window share the same name space (i.e.,
their mount table), and a
.CW mount ,
.CW bind ,
or
.CW unmount
done at a window will not in general be noticed at other ones. However,
.I any
process may have its own name space. This catches many users that have not
been using Plan 9 for some time, when they try to change the namespace using
Acme.
.PP
Figure [[!bind acme!]] shows a window running Acme. Using this acme, we executed
.P1
mkdir /tmp/dir ; bind /usr/nemo /tmp/dir
.P2
.LS
.BP acmebind.ps 3i
.LE F Executing a bind on Acme does not seem to work. What is happening?
.LP
(by selecting the text and then doing a click on it with the mouse button-2). Later,
we asked Acme to open
.CW /tmp/dir ,
using the mouse button-3. It was empty! What a surprise! Our home directory was
not empty, and after performing the
.CW bind ,
it seems that
.CW /tmp/dir
was not bound to our home directory. Is Acme broken?
.PP
Acme is behaving perfectly fine. When we used the mouse button 2 to execute the
command line, it created a child process to execute the command. The child process
prepared to execute the command and called
.CW rfork
with flags
.CW RFNAMEG|RFENVG|RFFDG|RFNOTEG .
Acme is just trying to isolate the child process. The flag
.CW RFNAMEG
caused the child process to obtain its own
.I copy
.ix [rfork]
of the name space used by Acme. As a result, any change performed to the name
space by the command you executed is unnoticed by Acme. The command starts,
changes its own name space, and dies.
.PP
To change this behavior, and ask Acme not to execute the child in its own
name space, you must use Acme's built-in command
.CW Local .
If a command is prefixed by
.CW Local ,
Acme understands that it must execute the command sharing its namespace with
the child process that will run the command. In this case, the child process will just
call
.CW rfork(RFFDG|RFNOTEG) ,
but it will share the namespace and environment variables with its parent (i.e., with
Acme). Figure [[!share name space acme!]] shows another attempt to change the name
space in Acme. The command executed this time was
.P1
Local mkdir /tmp/dir ; bind /usr/nemo /tmp/dir
.P2
.LP
and Acme executed
.P1
mkdir /tmp/dir ; bind /usr/nemo /tmp/dir
.P2
within its own name space. Note that
.CW Local
refers to the whole text executed as a command line, and not just to the first
command. This time, opening
.CW /tmp/dir
after the
.CW bind
shows the expected directory contents.
.LS
.BP acmebind2.ps 3i
.LE F Commands executed with \f(CWLocal\fP share their name space with Acme.
.PP
A related surprise may come from using the
.CW plumber ,
.ix [plumber]
.ix plumbing
.ix window
when you change the name space after starting it. The plumber has its own
name space, the one used by the shell that executed your
.CW $home/lib/profile ,
in case it was started from that file.
When the window system starts, it takes that name space as well. However,
the window system puts each window (process) in its own name space.
.PP
If there are three different windows running
Acme,
and you plumb a file name, the file will be open by all the Acmes running. This
is simple to understand, because all the editors are sharing the files at
.CW /mnt/plumb .
When you plumb a file name, the plumber sends the message to all editors
reading from the
.CW edit
port, as we saw.
.PP
But let's change the name space in a window, for example,
by executing
.P1
; 9fs whale
.P2
.LP
to mount at
.CW /n/whale
the file server named
.CW whale .
Here comes the surprise. When we try to plumb
.CW /n/whale/NOTICE ,
this is what we get.
.P1
; plumb /n/whale/NOTICE
; echo $status
plumb 1499: error
.P2
.LP
The plumber was unable to locate
.CW /n/whale/NOTICE .
After we mounted
.CW whale
on
.CW /n/whale !
.PP
But reconsider what happen. The shell running in the window is the one that
mounted
.CW /n/whale ,
the plumber is running using its own name space, far before our window was
brought to life. Therefore, the plumber does
.I not
have anything mounted at
.CW /n/whale .
It is our shell the one that has something mounted on it.
.PP
To change the name space for the plumber, a nice trick is used. The
.CW plumbing
.ix [plumbing]
file (containing the rules to customize plumbing) usually has one specific rule for
messages starting with the string
.CW Local .
This rule asks the plumber to execute the text after
.CW Local
in a shell started by the plumber. For example, we could do this:
.P1
; plumb 'Local 9fs whale'
; plumb /n/whale/NOTICE
; echo $status

;
.P2
.LP
The first command plumbs
.CW "Local 9fs whale" ,
which makes the plumber execute
.CW "9fs whale"
in a shell. Now, this shell is sharing the name space with the plumber. Thus,
the command plumbed
.I changes
the name space for the plumber. Afterwards, if we plumb
.CW /n/whale/NOTICE
the plumber will see that file and there will be no problem.
.PP
Is the problem solved? Maybe. After an editor is running at a different window,
receives the plumb message for
.CW /n/whale/NOTICE ,
it will not be able to open this file, because its name space is also different.
In general, this is not a problem at all, provided that you understand how you
are using your name spaces.
.PP
Another consequence of the per-process name spaces and the plumbing tool
is that you can isolate an editor regarding plumbing. Just do this:
.P1
; plumber
; acme
.P2
.LP
and the Acme will have its own set of plumbing files. Those files are supplied by
the plumber that you just started, which are different from the ones in use before
executing these commands.
.BS 2 "Device files
.LP
If you understood the discussion in the last section, this is a legitimate question:
How could my name space get anything mounted in the first place? To do a
mount, you must have a file where to do the mount. That is, you need a mount point.
.ix "mount point"
.ix "[#/] device driver
.ix "root device
.ix [/]
Initially, your machine is not even connected to the file server and you have just
what is inside your machine. You must have something that you could mount as
.CW /
in the first place.
.PP
Besides, you must be able to use your devices to reach the file server. This includes
.ix "device driver
.ix "file system
at least the network, and maybe the disk if you have your files stored locally in a
laptop. In Plan 9, the interface for using devices is a file tree provided by each
device driver (Remember, a device driver is just the program that drives your device,
and is usually linked inside the kernel).
That is to say that Plan 9
.I "device drivers are tiny file servers
that are
linked to the system.
.PP
You need to use the files provided by your drivers, which are their interface, if you
want to
use the devices. You want to use them to reach your file server across the network.
So, you have to mount these device file trees. And we are where we started.
.PP
The answer to this chicken-and-the-egg problem is a new kind of name that
we have silently omitted until now. You have absolute paths that start walking at
.CW / ,
you have relative paths that start walking at your current directory, and you also have
\fBdevice paths\fP
.ix "device path
.ix "[#] file names
that start walking at the root of the file tree of a device.
.PP
A device path starts with a hash “\f(CW#\fP” sign and a character (a rune in unicode)
that is unique for each device. The file
.CW /dev/drivers
.ix [/dev/drivers]
lists your device drivers, along with their paths:
.P1
; cat /dev/drivers
#/ root
#c cons
#P arch
#e env
#| pipe
#p proc
#M mnt
#s srv
.I "... others omitted
.P2
.LP
For example, the path
.CW #e
.ix "[#e] device driver
corresponds to the root directory of the file tree provided by the device
that keeps the environment variables.
Listing
.CW #e
(quoted, because the
.CW #
is special for the shell) gets the same file list than listing
.CW /env .
That is because
.CW #e
is bound at
.CW /env
by convention.
.P1
; lc /env
 '*'		cpu		init		planb
0		cputype		location	plumbsrv
.I "...and many others.
; lc '#e'
 '*'		cpu		init		planb
0		cputype		location	plumbsrv
.I "...and many others.
.P2
.LP
We have also seen that files at
.CW /proc
represent the processes in the system. Those files are provided by the
.I proc
device. To list the files for the process running the shell, we can
.ix "[#p] device driver
.P1
.ps -1
; lc /proc/$pid
args	fd	kregs	note	notepg	proc	regs
ctl	fpregs	mem	noteid	ns	profile	segment
.I "...and others.
.ps +1
.P2
.LP
But we can also
.P1
.ps -1
; lc '#p'/$pid
args	fd	kregs	note	notepg	proc	regs
ctl	fpregs	mem	noteid	ns	profile	segment
.I "...and others.
.ps +1
.P2
.LP
When a device path is used, the file tree for the device is automatically
mounted by the kernel. You might not even have where to mount it! The
rest of the name is resolved from there. Thus, device file names are always
available, even if you have no entries in your name space.
.PP
Where does
.CW /
come from? It comes from
.CW #/ ,
that is a tiny file tree that provides mount points to let you mount files
from other places. The device is called the
.CW root
device and includes the few programs necessary to reach your file server.
.P1
; lc '#/'
bin	dev	fd	net	proc	srv
boot	env	mnt	net.alt	root
.P2
.LP
This directory is bound to
.CW / ,
a few other mounts and binds made, and now you have your tree. The programs
needed to do this are also in there:
.P1
; lc '#//boot'
boot	factotum	fossil	ipconfig
.P2
.BS 2 "Unions
.LP
.ix "union mount
The mounts (and binds) we made so far have the effect of
.I replacing
the mount point file with the mounted file. This is what a mount table entry
does. However, you can also add a mounted file to the mount point. To see
how this works in a controlled way, let's create a few files.
.P1
; mkdir adir other
; touch adir/a adir/b adir/c
; touch other/a other/x other/y
; lc adir
a	b	c
.P2
.LP
If we bind
.CW other
into
.CW adir ,
we know what happens. From now on,
.CW adir
refers to
.CW other .
.P1
; bind other adir
; lc adir
a	x	y
.P2
.LP
After undoing the effect of the bind, to leave
.CW adir
undisturbed, we do another bind. But this time, we bind
.CW other
into
.CW adir
.I after
what it previously had, by using the
.CW -a
flag for
.CW bind .
.ix "[bind] flag~[-a]
.ix "[bind] flag~[-b]
And this is what we get:
.P1
; bind -a other adir
; lc adir
a	a	b	c	x	y
.P2
.LP
You can see how the file that used to be
.CW adir
now leads to a
.B union
of both the old
.CW adir
and
.CW other .
Its contents appear to be the union of the contents for both
directories. Because there are two files named
.CW a ,
one at the old
.CW adir
and another at
.CW other ,
we see that file name twice. Furthermore, look what happens here:
.P1
; rm adir/b
; lc adir
a	a	c	x	y
; rm adir/y
; lc adir
a	a	c	x
; lc other
a	x
.P2
.LP
Removing
.CW adir/b
removed the
.CW b
file from the original
.CW adir .
And removing the file
.CW adir/y
removed the file
.CW y ,
and of course the file is no longer at
.CW other
either. Let's continue the game:
.P1
; echo hola >other/a
; cat other/a
hola
; cat adir/a
;
.P2
.LP
We modify the file
.CW a
in
.CW other ,
and write something on it. Reading
.CW other/a
yields the expected result. However,
.CW adir/a
is still an empty file. Because we bound
.CW other
.I after ,
using the
.CW -a
flag for
.CW bind ,
the name
.CW a
is found in the old
.CW adir ,
which is
before the file with the same name in
.CW other .
Therefore, although we see twice
.CW a ,
we can only use the one that is first found.
.P1
; rm adir/a
; lc adir
a	c	x
; lc other
a	x
.P2
.LP
Removing
.CW adir/a
removes the file
.CW a
from the original
.CW adir .
But there is another file at
.CW other
named
.CW a ,
and we still see that name.
Because we bound
.CW other
into
.CW adir ,
.I after
what it previously had, the
.CW remove
system call finds first the name
.CW adir/a
at the old
.CW adir ,
and that is the one removed.
.PP
What happens to our name space?
How can it be what we saw above? The answer is that
you can bind (or mount) more than one file for the
.ix "mount point
same mount point. The mount table entry added by the bind
we made in this section is shown in figure [[!union mount entry!]].
.LS
.PS
.ps -2
boxwid=1
boxht=.4
[
	right
	box "Chan for" "\f(CWadir\fP"
	arrow right 1
	box "Chan for" "\f(CWadir\fP"
	arrow right 1
	box "Chan for" "\f(CWother\fP"
]
reset
.ps +2
.PE
.LE F A union mount. The mount entry after \f(CWbind -a other adir\fP. 
.PP
This entry has a mount point,
.CW adir .
When that file is reached, the name space jumps and continues walking
at the mounted file. However, here we have
.I two
mounted files for this entry. When we bound
.CW other
after what was initially at
.CW adir ,
Plan 9 added
.CW adir
as a file mounted here, and then
.CW other
was linked after as another mounted file. This can be seen if you use
.CW ns
to look for entries referring to
.CW adir :
.P1
; ns | grep adir
bind  /tmp/adir /tmp/adir 
bind -a /tmp/other /tmp/adir 
.P2
.LP
When a mount entry is a union, and has several mounted files,
the name space tries each one in order,
until one works for the name being resolved. When reading the directory,
.I all
of the feasible targets are read. Note that unions only make sense when
the files are directories.
By the way, to mount or bind
.I before
the previous contents of a union, use the flag
.CW -b
for either program.
.PP
Unions can be confusing, and
when you create files you want to be sure about where in the union
are you creating your files. To help, the flag
.CW -c
.ix "[bind] flag~[-c]
can be supplied to either
.CW bind
or
.CW mount
to allow you to create files in the file tree being mounted. If you do not supply
this flag,
you are not allowed to create files in there. When trying to create a file in
a union, the first file in the union mounted with
.CW -c
is the one used.
.BS 2 "Changing the name space
.LP
To adjust the name space in a C program, two system calls are available. They
are similar to the shell commands used above, which just call these functions
according to their command line arguments
.P1
.ps -2
; sig bind mount
	int bind(char *name, char *old, int flag)
	int mount(int fd, int afd, char *old, int flag, char *aname)
.ps +2
.P2
.LP
.ix [mount]
.ix [bind]
.ix "name space
The system call used by the
.CW mount
command we saw above is
.CW mount .
It takes a file descriptor,
.CW fd ,
used to reach the file server to mount. It must be open for reading and writing,
because a 9P conversation will go through it. The descriptor is usually a pipe or
a network connection, and must have a 9P speaker at the other end of the pipe.
To be on the safe side, Plan 9 closes
.CW fd
for your process after the mount has been done. This prevents you from reading
and writing that descriptor, which would disrupt the 9P conversation between Plan 9
and the file server.
.PP
After the call,
the
.CW old
file has the file server reached through
.CW fd
mounted on it.
The parameter
.CW aname
.ix [aname]
.ix "mount specifier
corresponds to the optional argument for the
.CW mount
command that names a particular file tree to be mounted. To mount
the server's main file free, supply an empty (not null!) string.
.PP
The options given to the shell command
.CW mount
are specified here using a bit-or of flags. You may use one of the
integer constants
.ix "[MREPL] mount~flag
.ix "[MBEFORE] mount~flag
.ix "[MAFTER] mount~flag
.ix "[MCREATE] mount~flag
.CW MREPL ,
.CW MBEFORE ,
and
.CW MAFTER .
Using
.CW MREPL
asks for
.I replacing
the old file (the mount point) with the new file tree. Using instead
.CW MBEFORE
asks
.CW mount
to mount the new file tree
.I before
the previous contents for the old file (equivalent to
.CW -b
in the shell command). Using
.CW MAFTER
instead asks for mounting the file tree
.I after
the old one (like giving a
.CW -a
to the shell command).
To allow creation of files in the mounted tree, do a bit-or of the
integer constant
.CW MCREATE
with any other flag.
.PP
This program mounts the main file tree of our file server at
.CW /n/whale ,
and the archive at
.CW /n/dump .
.so progs/whale.c.ms
.LP
Because the dump cannot be modified, we do not use
.CW MCREATE
for it, it would make no sense to try to create files in the (read-only) archive.
Running this program is equivalent to executing
.P1
; mount -c /srv/tcp!whale!9fs /n/whale
; mount /srv/tcp!whale!9fs /n/dump main/archive
.P2
.LP
As you could see, the program calls
.CW amount
.ix [amount]
.ix "authentication mount
and not
.CW mount .
The function
.CW amount
is similar to
.CW mount ,
but takes care of
.I authentication ,
i.e.,
convincing the file server that we are who we say we are. This is necessary or
the file server would not allow attaching to its file tree with the access rights
granted to our user name. After
.CW amount
convinces the file server, it calls
.CW mount
supplying an
.I "authentication file descriptor"
as the value for the
.CW mount
parameter
.CW afd .
.ix "authentication file descriptor
The other parameters for
.CW mount
are just those we gave to
.CW amount .
.PP
The other system call,
.CW bind ,
is used in the same way. Its flags are the same used for mount. However, unlike
mount, it receives a file
.CW name
instead of a file descriptor. As you could expect after having using the shell
command
.CW bind .
.BS 2 "Using names
.LP
We have seen that the shell has an environment variable,
.CW path ,
.ix "[path] variable
to determine where to search for commands. There are several interesting
things to note about this. First, there are only two directories where to search.
.P1
; echo $path
 .  /bin
;
.P2
.LP
This is really amazing if you compare this with the list of directories in the PATH
in other systems, which tends to be much larger.
For example, this is the variable used in a UNIX system we have
around:
.P1
$ echo $PATH
/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/opt/bin:.
$
.P2
.LP
In UNIX, the
.CW PATH
variable has the same name in upper-case, and directories
are separated by colons instead of space.
.PP
Also, how do you get at
.CW /bin
only those binaries for the architecture you are using?
.ix [/bin]
.ix "binary file
.PP
After your machine
has completed its boot process, and mounted the file server, it runs a program
called
.CW init .
This program initializes a new namespace for your terminal and runs
.CW /bin/rc
within such namespace, 
to execute commands in
.CW /rc/bin/termrc ,
.ix [termrc]
that start system services necessary for using the system.
The namespace is initialized by a call to
the function
.CW newns ,
.ix [newns]
.ix "new name space
.P1
; sig newns
	int newns(char *user, char *nsfile);
.P2
which reads a description for an entire namespace from a file,
.CW nsfile ,
and builds a new namespace for a given
.CW user
that matches such description. This is is an excerpt from the file
.CW /lib/namespace ,
which is the
.CW nsfile
used by default:
.P1
.SM
# root
mount -aC #s/boot /root $rootspec
bind -a /root /

# kernel devices
bind #c /dev
bind #d /fd
bind -c #e /env
bind #p /proc
bind -c #s /srv
.I "...several other binds...

# standard bin
bind /$cputype/bin /bin
bind -a /rc/bin /bin

# User mounts
bind -c /usr/$user/tmp /tmp
bind -bc /usr/$user/bin/$cputype /bin
bind -bc /usr/$user/bin/rc /bin
cd /usr/$user
.NS
.P2
.LP
As you can see, a namespace file for use with
.CW newns
contains lines similar to shell commands used to adjust the namespace, that
are like the ones in
.CW /proc/*/ns
files.
The file
.CW #s/boot
is a connection to the file server used to boot the machine. This is what
you find at
.CW /srv/boot ,
after the line
.P1
bind -c #s /srv
.P2
.LP
in the namespace file has been processed. Ignoring some details, you can
see how this file server is mounted at
.ix [/root]
.CW /root ,
and then this directory is added to
.CW / .
Both directories come from your root device,
.CW #/ ,
which is always available. 
The dance around
.CW /root
and
.CW /
.I adds
the root of the file server to those files already in
.CW /root .
.PP
The next few lines bind device driver file trees at conventional places.
For example,
.ix "console device
.ix "[#c] device driver
.CW #c
is the
.I cons
driver, which is bound at
.CW /dev
and provides files like
.CW /dev/null ,
.CW /dev/time ,
.ix [/dev/null]
.ix [/dev/time]
and other common files for the machine.
Also,
.CW #d
.ix "[#d] device driver
.ix "[/fd] file system
provides the file interface for your file descriptors, and is bound at
.CW /fd
as expected.
The same is done for other drivers.
.PP
Now look at the sections marked as
.I "standard bin" ,
and
.I "user mounts" .
They answer our question regarding
.CW /bin .
.PP
The program
.CW init
.ix [init]
.ix booting
defined several environment variables. For example,
.CW $user
holds your user name,
.CW $sysname
your machine name, and
.CW $home
your home directory. It also defined another variable,
.CW $cputype ,
which holds the name for the architecture it was compiled for. That is,
for the architecture you are using now! Therefore,
.ix [$user]
.ix [$sysname]
.ix [$home]
.ix [$cputype]
.ix "user name
.ix "system name
.ix "home directory
.ix "CPU type
.P1
bind /$cputype/bin /bin
bind -a /rc/bin /bin
.P2
.LP
binds
.CW /386/bin
into
.CW /bin ,
.ix 386
.ix "union
on a PC. All the binaries compiled for a 386 are now available at their
conventional place,
.CW /bin .
Besides, portable Rc scripts found at
.CW /rc/bin ,
which can be interpreted by
.CW rc
at any architecture, are added
to
.CW /bin ,
after the binaries just bound. You have now a complete
.CW /bin ,
all set for using. It that was not enough, the lines
.P1
bind -bc /usr/$user/bin/$cputype /bin
bind -bc /usr/$user/bin/rc /bin
.P2
.LP
add your own binaries and Rc scripts, that are stored at
.CW bin/386
(in this case) and
.CW bin/rc
in your home directory.
.PP
If you want to add, or remove, more binaries at
.CW /bin ,
you can just use
.CW bind ,
to customize
.CW /bin
as you please. There is no need for a longer
.CW $path ,
because
.CW /bin
may have just what you want. And you always know where your
binaries are, i.e., just look at
.CW /bin .
.PP
Another detail that you see is that the directory
.CW /tmp
is indeed
.CW /usr/$user/tmp .
You have your own directory for temporary files, although all programs
create them at
.CW /tmp ,
by convention. Even if the file system is being shared by multiple users,
each user has its own
.CW /tmp ,
to avoid disturbing others, and to avoid being disturbed.
.PP
We are going to continue showing how to use the name space to do a
variety of things. Nevertheless, if you want
to read a nice introduction to using name spaces for doing things, refer to
[.use name spaces.].
.BS 2 "Sand-boxing
.LP
.ix "sandboxing
Being able to customize the name space for a particular process is a very
powerful tool. For example, the window system does a
.P1
rfork(RFNAMEG)
.P2
to make a duplicate of the namespace it runs in, for each window (actually,
for each shell that is started for a new window). The shell script
.ix "[window] command
.P1
; window
.P2
.LP
creates a new Rio window, with a new shell on it. This shell is provided with its own copy
of the namespace, customized to use the console, mouse, and screen just for that
window. These are the commands:
.P1
rfork ne
mount /srv/rio.nemo.39 /mnt/wsys
bind -b /mnt/wsys /dev
.P2
.LP
.ix "window system
.ix "[rio] file system
Mounting the file server for the window system creates a new window, and
binding its file tree at
.CW /dev
replaces the files that represent the console. All the programs are unaware of this.
.PP
Many other things can be done. To freeze the time in your system, just provide
a file interface that never changes:
.P1
; cp /dev/time /dev/bintime /tmp/
; bind /tmp/time /dev/time
; bind /tmp/bintime /dev/bintime
.P2
.LP
One interesting use of namespaces is in creating sandboxes for processes to run.
A
.B sandbox
is a container of some kind that isolates a process to prevent it from doing any
damage, like when you do a sand box in the beach to contain the water.
This program creates a sandbox to run some code inside. It uses
.CW newns
to build a whole new namespace according to a file given as a parameter.
Because of the call to
.CW rfork(RFNOMNT)
.ix "no~attach
.ix "[RFNOMNT] [rfork]~flag
that follows, the process will not be allowed to mount any other file tree. It may
access just those files that are in the namespace described in the file. That is
a very nice sand box.
.ix [box.c]
.so progs/box.c.ms
.LP
The call to
.CW getuser
.ix [getuser]
returns a string with the user name. We have already seen all other calls
used in this program. The program can be used like in
.P1
; 8.box sandbox /bin/rc
.P2
.LP
Where
.CW sandbox
is a file similar to
.CW /lib/namespace ,
.ix [/lib/namespace]
.ix "standard name~space
but with mounts and binds appropriate for a sandbox.
.BS 2 "Distributed computing revisited
.LP
.ix "distributed computing
.ix "remote execution
.ix "import
.ix "remote file~system
.ix "CPU server
In the last chapter, we learned about CPU servers and connected to one
of them to execute commands. But there is one interesting thing about that
kind of connection. Indeed, you have already seen it, but perhaps it went unnoticed.
This thing may become more visible if you connect to a cpu server and execute
.CW rio .
The result is shown in figure [[!rio cpu!]].
.LS
.BP cpurio.ps
.LE F Rio run in a Rio window. The inner rio runs at a CPU server, not at your terminal.
.P1
; cpu
cpu% !!rio
.I "...and you get a whole window system in your window!
.P2
.LP
You just started the window system, but it is running at the CPU server, and not
at your terminal. However, it is using your mouse, your keyboard, and your screen
to do its job! Not exactly, indeed, it is using the virtual mouse, keyboard, and screen
provided by the Rio in your terminal for the window you used to connect to the
CPU server. Is it magic?
.PP
The answer may come if you take a look at the name space used by a shell
obtained by connecting to a CPU server. This shell has a namespace that has
at
.ix [/mnt/term]
.ix "terminal file~system
.CW /mnt/term
the whole namespace you had available in the window where you did run
.CW cpu .
.ix [cpu]
Furthermore, some of the files at
.CW /mnt/term/dev
were bound to
.CW /dev .
.ix [/dev]
Therefore, many of the devices used by the shell (or any other process) in the CPU server
do not come from the CPU server itself. They come from your terminal!
.PP
The namespace at your terminal includes files like
.CW /dev/cons ,
.CW /dev/draw ,
and
.CW /dev/mouse .
.ix [/dev/mouse]
.ix [/dev/draw]
This name space was initialized by
a process that called
.CW newns
using
.CW /lib/namespace ,
as we saw in another example before, and then perhaps you customized
it further by doing mounts or
binds in your profile. The same happens for the shell started for you in the CPU server.
It gets a namespace initialized by a call to
.CW newns ,
and perhaps by your profile.
However, the program initializing a namespace for you in the CPU server
mounted at
.CW /mnt/term
the name space exported from your terminal, and made a few binds to
adjust
.CW /dev
to use your terminal's devices instead.
.PP
This includes the files we mentioned above
that are the interface for your console, for drawing graphics, and for using
the mouse. At least, they are within your terminal's window. At a different window, you know
that rio provides different files that represent the interface for the console, graphics,
and mouse for that other window.
.PP
Now the question remains. How can a namespace be exported?
Change the question. How can a namespace be imported? To import
anything into your namespace, you must mount a 9P file server. Therefore,
if your namespace is exported using a file server, it can be imported.
It turns out that there is a program for doing just that. Well, there are two.
.PP
The real work is done by
.CW exportfs .
.ix [exportfs]
.ix "file~system export
This program uses the venerable calls
.CW open ,
.CW close ,
.CW read ,
.CW write ,
etc. to access your namespace, and exports it by speaking 9P through a network
connection, like any other file server. When a 9P client of
.CW exportfs
asks this program to return the result of reading a file, it reads the file
and replies. When a 9P client asks
.CW exportfs
to write into a file, by sending a 9P write request to it, the program uses the
.CW write
system call to write to the file. The effect is that for anyone mounting the file
tree provided by
.CW exportfs ,
that file tree is exactly the same than the one in effect in the namespace where
.CW exportfs
runs.
.PP
The second program
that can be used to export a namespace,
.ix [srvfs]
.ix [/srv]
.CW srvfs ,
is just a convenience
wrapper, that calls
.CW exportfs
in a way that is simpler to use from the shell. It receives the name for
a file to be created at
.CW /srv ,
that when mounted, grants access to the file tree rooted at the directory given
as the second argument.
.PP
To see that
.CW srvfs ,
i.e.,
.CW exportfs ,
is indeed exporting a namespace, we can rearrange a little bit
our namespace, export a part of it, and see how after mounting it
we gain access to the rearranged file tree that we see, and not the real one from the
file server.
.P1
; mkdir /tmp/exported /tmp/exported/doc /tmp/exported/src
; bind $home/doc /tmp/exported/doc
; bind $home/src /tmp/exported/src
; 
; srvfs x /tmp/exported
; 
; mount -c /srv/x /n/imported
; lc /n/imported
doc	src
; lc /n/imported/src
9		gs		misc
UGrad		lang		os
bbug		limbo		prj
chem		mem		sh
.P2
.LP
A nice example of a use for this program can be found
in the
.I srvfs (4)
manual page.
.P1
; cpu
cpu% !!srvfs procs /mnt/term/proc
cpu%
.P2
.ix "remote debugging
This posts at
.CW /srv/procs ,
in the CPU server,
a file descriptor that can be used to mount the file tree seen at
.CW /mnt/term/proc
in the namespace where
.CW srvfs
is executed. That is, the
.CW /proc
file tree at the terminal used to run the
.CW cpu
command.
Therefore, mounting
.CW /srv/procs
in the CPU server
permits obtaining access to the
.CW /proc
interface for the user's terminal.
.P1
cpu% !!mount -c /srv/proc /n/procs
cpu% !!lc /n/procs
1	20	257	30	33	367	662
10	21	259	300	330	37	663
11	213	26	305	334	38	669
111	214	260	306	335	387	674
12	22	265	310	34	389	676
13	23	266	311	346	39	677
;
.P2
.LP
Remember, because almost every resource looks like a file, you can
now export whatever resource you may want.
.PP
Indeed, we do not even need to use
.CW cpu
to connect to the CPU server to mount the exported
.CW /proc ,
we can
.I import
the directory
.CW /srv
from the CPU server, and mount it at our terminal:
.P1
; import $cpu /srv /n/cpusrv
; mount -c /n/cpusrv/proc /n/procs
.P2
.LP
The program
.CW import
is the counterpart of
.CW exportfs .
It imports a part of a remote namespace into our namespace.
What it does is to connect to the remote system, and start an
.CW exportfs
there, to export file tree of interest. And then, it mounts the now
exported file tree in our namespace.
.PP
For example, the file name
.CW #S
.ix "storage device driver
.ix "[#S] device driver
.ix [sdC0]
is the root directory for the storage device driver. This driver provides
one directory per hard disk, which contains one file per partition in the disk.
It doesn't really matter how a disk interface looks like, or how a disk is managed
in Plan 9. What matters is that this is the way to get access to the disks in your
system, for example, to format them. My terminal has two hard disks and a DVD reader.
.P1
; lc '#S'
sdC0	sdC1	sdD0	sdctl
.P2
.LP
They are named
.CW sdC0 ,
.CW sdC1 ,
and
.CW sdD0. Because
.CW #S
is usually added to
.CW /dev
using
.CW bind ,
some of these files are likely to show up in your
.CW /dev .
.PP
If you want to format a hard disk found at a remote
machine, you may do so from your terminal. Imagine the disk is at your CPU
server, you might do what follows.
.P1
; import $cpu '#S' /n/cpudisks
; lc /n/cpudisks
sdC0	sdC1	sdD0	sdD1 sdctl
;
.P2
.LP
If you do not have a floppy reader unit at your terminals (which is the
common case today for laptops), there is no need to worry.
You can import
.CW #f ,
the root directory for the floppy disk driver, from another machine. And then
use the script
.CW a: ,
which mounts the DOS formatted floppy of your terminal at
.CW /n/a .
.P1
; import -bc barracuda '#f' /dev
; a:
; cp afile /n/a/afile.txt
; unmount /n/a
.P2
.LP
As you could see,
.CW import
admits the same familiar options for
.CW mount
and
.CW bind ,
to mount the imported tree before, after, or replacing part of your namespace.
.PP
.ix "firewall
This applies to the the serial port, the audio card, and any other resource that any
other machine might have,  provided it is represented as a file. As a final example,
firewalls are machines that are connected to two different networks, one protected
network for local use, and the internet. In many cases, connecting directly to
the internet from the local network is forbidden, to create a firewall for viruses and
malicious programs. Nevertheless, if the firewall network for connecting to the
Internet is
.CW /net.alt ,
at the firewall machine, this grants your machine direct connection to the internet
as well (at the price of some danger).
.P1
; import -c firewall /net.alt /net
.P2
.SH
Problems
.IP 1
Add the line
.P1
rfork(RFNAMEG);
.P2
.IP
to the program
.CW whale ,
before doing the calls to
.CW amount ,
and see what happens when you execute it. Explain.
.IP 2
Enumerate the file servers available at your local Plan 9 site.
.IP 3
Print down the name space used by the plumber in your session.
.IP 4
Reproduce your name space at a different machine.
.IP 5
Make your system believe that it has an extra CD unit installed. Use it.
.IP 6
Put any server you have implemented in a sand-box. Try to break it.
.ds CH
.bp
 \c
.bp
 \c