1

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).

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • I do not understand - you want to have the path some symlink points to or you want to resolve all symlinks in a path? I.e. you want realpath() or readlinke() ? – KamilCuk Oct 09 '22 at 08:15
  • @KamilCuk In simple words, I want one with symlinks.(i.e. not resolve them) – Aspect Karlos Oct 09 '22 at 08:22
  • The current working directory is like always the one without symlinks. It seems to me that _you_ have to store the one with symlinks in your program and manage it youself. – KamilCuk Oct 09 '22 at 08:38
  • I see... By the way, is that also how it is implemented in the default bash shell? – Aspect Karlos Oct 09 '22 at 08:45

1 Answers1

2

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.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • So basically I can get the value of the `PWD` variable using `getenv()`, and that will give me the same output that I would have gotten by executing the `pwd` command in the shell..? – Aspect Karlos Oct 09 '22 at 08:39
  • @AspectKarlos: yes and the `PWD` variable must be properly maintained as a side effect of the `cd` / `chdir` shell commands. I updated the answer with more gory details about this. – chqrlie Oct 09 '22 at 08:47