csymlinkchdir

Implementation of the command cd (cd -L) in C without exec functions


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 !


Solution

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