Lexical File Names in Plan 9

or

Getting Dot-Dot Right

Rob Pike

rob@plan9.bell-labs.com

Bell Laboratories

Murray Hill, New Jersey 07974

ABSTRACT

Symbolic links make the Unix file system non-hierarchical, resulting in multiple valid path names for a given file. This ambiguity is a source of confusion, especially since some shells work overtime to present a consistent view from programs such as pwd, while other programs and the kernel itself do nothing about the problem.

Plan 9 has no symbolic links but it does have other mechanisms that produce the same difficulty. Moreover, Plan 9 is founded on the ability to control a program’s environment by manipulating its name space. Ambiguous names muddle the result of operations such as copying a name space across the network.

To address these problems, the Plan 9 kernel has been modified to maintain an accurate path name for every active file (open file, working directory, mount table entry) in the system. The definition of ‘accurate’ is that the path name for a file is guaranteed to be the rooted, absolute name the program used to acquire it. These names are maintained by an efficient method that combines lexical processing—such as evaluating .. by just removing the last path name element of a directory—with local operations within the file system to maintain a consistently, easily understood view of the name system. Ambiguous situations are resolved by examining the lexically maintained names themselves.

A new kernel call, fd2path, returns the file name associated with an open file, permitting the use of reliable names to improve system services ranging from pwd to debugging. Although this work was done in Plan 9, Unix systems could also benefit from the addition of a method to recover the accurate name of an open file or the current directory.

Motivation

Consider the following unedited transcript of a session running the Bourne shell on a modern Unix system:

% echo $HOME

/home/rob

% cd $HOME

% pwd

/n/bopp/v7/rob

% cd /home/rob

% cd /home/ken

% cd ../rob

../rob: bad directory

(The same output results from running tcsh; we’ll discuss ksh in a moment.) To a neophyte being schooled in the delights of a hierarchical file name space, this behavior must be baffling. It is, of course, the consequence of a series of symbolic links intended to give users the illusion they share a disk, when in fact their files are scattered over several devices:

% ls -ld /home/rob /home/ken

lrwxr-xr-x  1 root  sys   14 Dec 26  1998 /home/ken -> /n/bopp/v6/ken

lrwxr-xr-x  1 root  sys   14 Dec 23  1998 /home/rob -> /n/bopp/v7/rob

The introduction of symbolic links has changed the Unix file system from a true hierarchy into a directed graph, rendering .. ambiguous and sowing confusion.

Unix popularized hierarchical naming, but the introduction of symbolic links made its naming irregular. Worse, the pwd command, through the underlying getwd library routine, uses a tricky, expensive algorithm that often delivers the wrong answer. Starting from the current directory, getwd opens the parent, .., and searches it for an entry whose i-number matches the current directory; the matching entry is the final path element of the ultimate result. Applying this process iteratively, getwd works back towards the root. Since getwd knows nothing about symbolic links, it will recover surprising names for directories reached by them, as illustrated by the example; the backward paths getwd traverses will not backtrack across the links.

Partly for efficiency and partly to make cd and pwd more predictable, the Korn shell ksh [Korn94] implements pwd as a builtin. (The cd command must be a builtin in any shell, since the current directory is unique to each process.) Ksh maintains its own private view of the file system to try to disguise symbolic links; in particular, cd and pwd involve some lexical processing (somewhat like the cleanname function discussed later in this paper), augmented by heuristics such as examining the environment for names like $HOME and $PWD to assist initialization of the state of the private view. [Korn00]

This transcript begins with a Bourne shell running:

% cd /home/rob

% pwd

/n/bopp/v7/rob

% ksh

$ pwd

/home/rob

This result is encouraging. Another example, again starting from a Bourne shell:

% cd /home/rob

% cd ../ken

../ken: bad directory

% ksh

$ pwd

/home/rob

$ cd ../ken

$ pwd

/home/ken

$

By doing extra work, the Korn shell is providing more sensible behavior, but it is easy to defeat:

% cd /home/rob

% pwd

/n/bopp/v7/rob

% cd bin

% pwd

/n/bopp/v7/rob/bin

% ksh

$ pwd

/n/bopp/v7/rob/bin

$ exit

% cd /home/ken

% pwd

/n/bopp/v6/ken

% ksh

$ pwd

/n/bopp/v6/ken

In these examples, ksh’s built-in pwd failed to produce the results (/home/rob/bin and /home/ken) that the previous example might have led us to expect. The Korn shell is hiding the problem, not solving it, and in fact is not even hiding it very well.

A deeper question is whether the shell should even be trying to make pwd and cd do a better job. If it does, then the getwd library call and every program that uses it will behave differently from the shell, a situation that is sure to confuse. Moreover, the ability to change directory to ../ken with the Korn shell’s cd command but not with the

This transcript begins with a Bourne shell running:

% cd /home/rob

% pwd

/n/bopp/v7/rob

% ksh

$ pwd

/home/rob

This result is encouraging. Another example, again starting from a Bourne shell:

% cd /home/rob

% cd ../ken

../ken: bad directory

% ksh<