Search code examples
clinuxsymlinkpwdgetcwd

How to get the current path with symlink (not the actual path) in a c program on a linux system?


I am currently building a custom shell that can handle a few internal and external commands along with their options. One of these internal commands is pwd. From the man page of pwd, I got that pwd -L is going to output the current working directory even if it contains symlinks.

Now for implementing this, I want to know what functionality is available in C that can provide the working directory without resolving symlinks.

OS: GNU/Linux

PS: getcwd() gives the actual path and resolves the symlink. (Correct me if I am wrong somewhere).


Solution

  • The pwd command has 2 different modes:

    • pwd -L displays the logical current working directory.

    • pwd -P displays the physical current working directory (all symbolic links resolved).

    If no options are specified, the -L option is assumed.

    pwd -P uses the getcwd() function: it resolves the .. chain from the current directory of the process.

    Starting from the current directory, whose inode and device number are retrieved, it opens the parent directory as with opendir("..") and enumerates the entries until one is found with the same inode and device number. This entry is the last component of the current directory name. If no such entry is found, getcwd() fails and sets errno to ENOENT.

    The process keeps going on the next parent directory until the root directory is reached.

    This is very inefficient. pwd -L, which is the default, uses a different method: the shell maintains an environment variable PWD that contains the unresolved path to the current directory as reached by the shell via chdir/cd commands. This path may differ from that obtained by getcwd() if symbolic links were followed to reach the current directory or if some parts of the path have been renamed, moved or even removed. Thus the path stored in $PWD may not even exist anymore, or may lead to a different place.

    To implement pwd -L in your shell, you can just output the value of the PWD environment variable, and you should update this variable when you execute chdir / cd shell commands.

    Note also that for this chdir / cd command, paths relative to the current directory should be resolved logically relative to this unresolved path by dropping the previous component for each ../ in the destination path. Only the resulting string that contains no . or .. component is passed to the OS via the chdir system call.