Why does '/' contain '..'?
The ..
entry in the root directory is a special case.
From the POSIX standard (4.13 Pathname Resolution, where the .
and ..
entries are referred to as "dot" and "dot-dot" repsectively):
The special filename dot shall refer to the directory specified by its predecessor. The special filename dot-dot shall refer to the parent directory of its predecessor directory. As a special case, in the root directory, dot-dot may refer to the root directory itself.
The rationale has this to add (A.4.13 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-2017. 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. [...]
So, in short, the POSIX standard says that every directory should have both .
and ..
entries, and permits the ..
directory entry in /
to refer to the /
directory itself (notice the word "may" in the first text quoted), but it also allows an implementation to let it refer to something else.
Most common implementations of filesystems makes /..
resolve to /
.
Kusalananda has already told you that this is the behavior specified by the POSIX standard. However, the history of UNIX began in earnest in the early 1970s. POSIX dates back only to the second half of the 1980s, a full decade and a half later. In practice, POSIX merely specified what was already being done by implementations.
Rather, UNIX did very early on support mounting file systems on different devices into its single unified directory hierarchy. Each file system, in effect, has its own root directory; the file system mounted at /
isn't particularly special in any way. (Its contents might be, but the file system itself isn't.)
The sysmount
and sysumount
system calls appear to have been introduced in UNIX V1, in 1970-1971 (V1 is dated 1971-11, according to the Unix Tree at The Unix Heritage Society). They are defined in u1.s (system call numbers 21 and 22, respectively) and implemented in u7.s. (PDP7 UNIX, dated 1970-01, does not appear to have any obvious ancestor of those).
You probably see where this is going: when any file system can be mounted at any location in the hierarchy, to keep from having to special-case things, each directory, including the root directory of each file system, should contain an entry pointing to its own parent directory. On disk, the logical place to point a file system's root directory's parent directory entry at is the file system's root directory, because there is nothing else "above" the file system's root directory. The concept of having something "above" the root directory only comes into play when that file system is mounted at some location other than the root of the hierarchy.
During mounting, it is possible to rewrite the "parent directory" pointer in the memory copy of the root directory to point at the parent directory of the mount point directory. If there is no parent directory of the mount point directory (in other words, the file system is being mounted as /
), then just leave that piece of data alone (because there's likely nowhere else sensible to point it to anyway) or handle it separately later (as would probably be the case for the /../hostname/path
and //hostname/path
cases mentioned in Kusalananda's answer).
The resulting behavior is that in any directory other than /
, regardless of whether it's a particular file system's root directory or a subdirectory (at any level of nesting), ..
points at that directory's parent directory; and in /
, ..
points back at /
. The former is what would feel natural (..
always works in the same way, moving you one step toward the root directory), while the latter, while slightly idiosyncratic, at least doesn't obviously break anything (there's little harm in not being able to move further toward the root directory than to the root directory itself). For example, you can hammer out an arbitrary number of ../
and know that those at least will not cause an error because ..
at some point does not exist.
There is a directory above /
, /
itself. The parent directory of the root directory is itself. cd ..
or cd ../..
inside the root directory should leave you at the same place, not cause an error.
Notice that neither .
or ..
may exist as actual directory entries in some filesystems, they may be simply emulated by the virtual file system layer of the OS.
A path like /../hostname
is supposed to have let you access the root of another host in some early pre-vfs and pre-nfs systems like MUNIX (using the "Newcastle Connection") but I don't know of any such system still in use, and the source code is nowhere to be found.
The available info is highly contradictory, but it seems that the most usual way to deploy such a system was by recompiling all programs so that all path-using calls like open(2)
could be redirected in userspace (there were no shared libs in that time).
There were probably hundreds of such hacks (scratchbox being a more recent one that I had the displeasure of having to use), so it's not at all clear why they felt the need to accomodate it in the POSIX standard.