[Gllug] Filesystem root directory oddity

Nix nix at esperi.org.uk
Wed Mar 18 00:25:00 UTC 2009


On 17 Mar 2009, John Winters said:

> Richard Huxton wrote:
>> $ cd /; pwd; cd //; pwd; cd ///; pwd cd ////; pwd
>> /
>> //
>> /
>> /
>
> If you invoke /bin/pwd instead of the in-built pwd you get a correct
> location of "/" for every case.  AFAICR the shell's in-built pwd uses a
> sort of "remember where you last moved to" strategy to produce its
> results.  It looks to me like you might have tickled a small bug in your
> shell.

It's not a bug, but a feature. bash is making allowances for a strange
special case in POSIX, that there can be a distinct 'superroot'
namespace starting with //. (Any other series of leading slashes is
collapsed to a single slash.)

Chapter and verse from POSIX.1-2008:

,----[ 4.12 Pathname Resolution ]
| A pathname consisting of a single <slash> shall resolve to the root
| directory of the process. A null pathname shall not be successfully
| resolved. A pathname that begins with two successive <slash> characters
| may be interpreted in an implementation-defined manner, although more
| than two leading <slash> characters shall be treated as a single <slash>
| character.
`----

The rationale explains this:

,----[ A.4.12 Pathname Resolution ]
| What the filename dot-dot refers to relative to the root directory is
| implementation-defined. In Version 7 it refers to the root directory
| itself; this is the behavior mentioned in POSIX.1-2008. In some
| networked systems the construction /../hostname/ is used to refer to the
| root directory of another host, and POSIX.1 permits this behavior.
| 
| Other networked systems use the construct //hostname for the same
| purpose; that is, a double initial <slash> is used. There is a potential
| problem with existing applications that create full pathnames by taking
| a trunk and a relative pathname and making them into a single string
| separated by '/', because they can accidentally create networked
| pathnames when the trunk is '/'. This practice is not prohibited
| because such applications can be made to conform by simply changing to
| use "//" as a separator instead of '/':
| 
| - If the trunk is '/', the full pathname will begin with "///" (the
|   initial '/' and the separator "//" ). This is the same as '/', which is
|   what is desired. (This is the general case of making a relative pathname
|   into an absolute one by prefixing with "///" instead of '/'.)
| 
| - If the trunk is "/A", the result is "/A//..."; since non-leading
|   sequences of two or more <slash> characters are treated as a single
|   <slash>, this is equivalent to the desired "/A/...".
| 
| - If the trunk is "//A", the implementation-defined semantics will
|   apply. (The multiple <slash> rule would apply.)
| 
| Application developers should avoid generating pathnames that start with
| "//". Implementations are strongly encouraged to avoid using this
| special interpretation since a number of applications currently do not
| follow this practice and may inadvertently generate "//...".
`----

Historically, these somewhat peculiar semantics were originally
specified for the sake of a number of ancient Unixes (notably Pyramid's)
which had SysV and BSD stuff segregated into separate 'universes',
delineated via //-preceded paths; but it proved useful when SMB came
along.

Inside bash, this is implemented in lib/sh/pathphys.c: search for
'DOUBLE_SLASH'. zsh handles double slashes specially in the 'h' history
modifier and in the completion system, but doesn't bother to preserve
them specially in pwd output: it trusts the OS to do that where it
matters.


I am somewhat disturbed by how much of this I knew without having to
look it up. Can someone donate a life, please?
-- 
Gllug mailing list  -  Gllug at gllug.org.uk
http://lists.gllug.org.uk/mailman/listinfo/gllug




More information about the GLLUG mailing list