1

I'm trying to code the command cd in C without using the exec functions, I already did the cd -P version but I can't seem to find a way to do cd (cd -L) because the function chdir resolves the symlinks so my cd -L acts like cd -P.

For cd -P I did one function which takes the path we want to get to as a parameter and I have a variable old_pwd that acts like $OLDPWD in my file (I use getenv("PWD") to initialize it), if the parameter is empty I just use chdir on $HOME, if the parameter is "-" I use chdir on the variable old_pwd and finally if its a path I use chdir on that path. If you have an idea on how to change the current directory without resolving any symlink I will be very grateful !

Chae
  • 13
  • 3
  • `cd` can't be implemented as a **program**, only as a command within some other program (like the shell). What's the context here? – Davis Herring Nov 20 '22 at 21:16
  • @DavisHerring, I take the OP to be talking about implementing `cd` in the context of a custom shell. Nevertheless, POSIX does require that `cd`, as a standard utility and not a "special built-in" one, be available as a command that can be accessed via the `exec` family of functions. Interestingly enough, however, although both my Linux workstation and my Mac indeed do provide such an external `cd` command, their `/bin/cd` and `/usr/bin/cd`, respectively, do not produce behavior consistent with the POSIX specs. – John Bollinger Nov 21 '22 at 19:10
  • I am trying to make my own shell in C, I am making different files for the commands that I want to implement and right now I'm focusing on `cd` using `chdir`. The problem I was trying to explain is that I do not want to follow any symbolic link in the path but since `chdir` resolves them I can't figure a solution. I tried to understand the algorithm gave by @JohnBollinger but I am not sure I truly understood it and if the example I gave bellow was wrong. – Chae Nov 21 '22 at 19:43
  • @JohnBollinger: Interesting: some of my systems don't have any `cd` on `PATH`, and the ones that do have it as a shell script! Nor do I [see](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/cd.html) the requirement that it be a program. In any case, you were right about the context here. – Davis Herring Nov 21 '22 at 21:57
  • 1
    @DavisHerring, it is a general requirement of *all* standard POSIX utilities (which `cd` is) other than special built-in utilities (which `cd` is not) that they be available in a form that can be exercised via the `exec` family of functions. This is in [section 1.6 of the *Shell and Utilities* chapter of POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tag_17_06). – John Bollinger Nov 21 '22 at 23:00

1 Answers1

0

POSIX Path resolution works through a path stepwise, from beginning to end, resolving symlinks as it goes. This is how POSIX chdir() interprets paths, and it is consistent with the behavior of cd -P.

cd -L requires different behavior: that steps of the form .. be interpreted relative to the other literal steps in the given path, regardless of whether any steps designate symbolic links. That behavior differs from chdir()'s, so you have to implement it yourself. This is largely a matter of parsing and processing appearances of . and .. in the path before handing off the result to chdir().

The POSIX specs for cd, linked above, provide a detailed algorithm for how cd -L should perform the needed path manipulations. As such, I have removed the algorithm I presented in an earlier version of this answer, and replaced the notes regarding it with notes pertaining to the official POSIX specifications.

Notes:

  1. POSIX defines an obscure environment variable CDPATH and some directory-search semantics for cd associated with that. Details are in the linked specs. If you're going for full POSIX semantics then you'll need to handle that; otherwise, I doubt whether very many people would notice the absence of that feature.

  2. The effect of -P is to pass the specified path to chdir() as-is, provided that any target path is in fact specified, or to pass the value of $HOME to chdir() if no path is otherwise specified.

  3. When -L is in effect, relative paths are interpreted with respect to the current value of $PWD. Processing of leading .. path steps takes that into account.

  4. POSIX specifies that .. processing causes cd to fail with an error if the leading path preceding the .., interpreted according to the standard path-resolution rule (including symlink traversal), does not designate a directory. That is,

    • dir1/dir2/.. and dir1/symlink-to-dir3/.. are both ok, and both are equivalent to dir1, but

    • dir1/regular-file/.., dir1/not-a-filename/.., and similar are erroneous.

  5. The -L behavior is the default if neither -P nor -L is given.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Hi thank you for your reply I just wanted to get some clarifications : If I have directories like this : `test/dir1/dir2/dir3` and `test/dir4` with `test/dir4 -> test/dir1/dir2/dir3` a symbolic link If I'm in `dir4` and I want to get to `test` and not `dir2` by using `cd ..` the path will not change with the algorithm you gave but if I use `chdir` on `..` it will still get me to `dir2` and not `test` because it will follow the symbolic link in `dir4` So should `..` change with this algorithm ? – Chae Nov 21 '22 at 18:26
  • @Chae, I have performed a major revision of this answer. It now refers you to the official POSIX specifications for `cd`, which include their own algorithm for how `cd -L` must mangle paths. This does take the shell's idea of the path to the current working directory (from `$PWD`) into account when `-P` is not in effect. – John Bollinger Nov 21 '22 at 19:50