开发者

A confusion in APUE2(about symbolic link in UNIX)

开发者 https://www.devze.com 2023-04-07 09:43 出处:网络
The original text is below.It is in Section 4.22 The program in Figure 4.24 changes to a specific directory and then calls getcwd to print the working directory. If we run the program, we get

The original text is below.It is in Section 4.22

The program in Figure 4.24 changes to a specific directory and then calls getcwd to print the working directory. If we run the program, we get

$ ./a.out
cwd = /var/spool/uucppublic
$ ls -l /usr/spool
lrwxrwxrwx 1 root 12 Jan 31 07:57 /usr/spool -> ../var/spool

Note that chdir follows the symbolic link as we expect it to, from Figure 4.17 .but when it 开发者_Python百科goes up the directory tree, getcwd has no idea when it hits the /var/spool directory that it is pointed to by the symbolic link /usr/spool. This is a characteristic of symbolic links.

What does the author really mean by saying that the program hits the /var/spool? What is the characteristic of symbolic links pointed out by the author? I did not really understand.


Note that some shells, notably bash, keep track of whether you arrived at a given directory by chasing a symbolic link, and print the current directory accordingly. At least bash has options to cd to do a physical or logical change directory:

cd [-L|-P] [dir]

Change the current directory to dir. The variable HOME is the default dir. [...] The -P option says to use the physical directory structure instead of following symbolic links (see also the -P option to the set builtin command); the -L option forces symbolic links to be followed. An argument of - is equivalent to $OLDPWD. If a non-empty directory name from CDPATH is used, or if - is the first argument, and the directory change is successful, the absolute pathname of the new working directory is written to the standard output. The return value is true if the directory was successfully changed; false otherwise.

In the scenario shown, where /usr/spool is a symbolic link to /var/spool, then:

$ pwd
/
$ cd /usr/spool/uucppublic
/usr/spool/uucppublic
$ cd -L ..
/usr/spool
$ cd /usr/spool/uucppublic
/usr/spool/uucppublic
$ cd -P ..
/var/spool
$

For most people, a plain cd .. would do the same as cd -L ... You can choose to have bash do the same as cd -P .. instead if you prefer (using set -P or set -L).

The process of finding the pathname of the current directory should be understood too. Logically, the process (kernel) opens the current directory (.) and reads the inode number (and device number). It then opens the parent directory (..), and reads entries from that until it finds one with the matching inode number (and device number). This then gives it the last component of the pathname. It can now repeat the process, finding the the inode number of the next directory up, and opening its parent directory (../..), etc, until it reaches the root directory (where the inode number for both . and .. is the same, and the value is conventionally 2). Note that this even works across mount points. Beware of auto-mounted remote (NFS) file systems, though; it can be really slow if you scan through a directory containing several hundred automounted machines - as the naïve search outline above mounts all the machines until it finds the correct one. So, actual getcwd() functions are cleverer than this, but it explains how the path of the current directory is found. And it also shows why the process will not encounter /usr/spool when evaluating the directory under /var/spool/uucppublic - it simply never opens the /usr directory.

Note that the realpath() function (system call) takes a name possibly referencing symlinks and resolves it to a name that contains no symlinks at all. Passed /usr/spool/uucppublic, it would return /var/spool/uucppublic, for example.


Expanding on what @undor_gongor wrote:

Each process has a current working directory. It's not stored as the path name of the directory; it's a reference to the directory itself.

If it were stored as a path name, then the getcwd() function's job would be trivial: just print the path name. Instead, it has to readi the current directory, open its .. entry, then open that directory's .. entry, and so forth until it reaches the root (i.e., a directory whose .. entry points to the directory itself). It builds up the full path of the current directory in reverse order as it does this.

Since .. can't be a symlink, this process is not affected by symbolic links.

(Shells might have a $PWD or $CWD variable, or a pwd built-in, that is affected by symlinks; these typically work by remembering the string that was passed to cd or pushd.)


Assume you have a symlink /usr/spool pointing to /var/spool.

It says if you follow that symlink (e.g. cd /usr/spool), you end up in the pointed-to directory (/var/spool). Then, the information that you followed a symlink is lost. You are in /var/spool as if you had done cd /var/spool directly.

A further cd .. brings you to /var (as opposed to /usr).

UPDATE:

As pointed out by Keith Thompson and Jonathan Leffler, there are some shells that do remember the path you followed (i.e. /usr/spool). In such shells, cd .. would go to /usr/. However, programs started from such a shell would still see /var/spool as the working directory.

This is probably the reason the author let you write a program for displaying cwd (to work-around such shells' internals).

0

精彩评论

暂无评论...
验证码 换一张
取 消