Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

can we have an option for cd to do a plain chdir()



I was surprised to see that after:

ln -s /proc/self/cwd/.. link; cd link

I ended up two directories up instead of one.

strace revealed:

$ strace -fe getcwd,readlink,chdir,fchdir zsh -c 'cd link'
readlink("/proc/self/fd/0", "/dev/pts/4", 4095) = 10
chdir("/home/chazelas/link")            = 0
chdir("/home/chazelas/link")            = 0
+++ exited with 0 +++

Not sure why the two chdir()s there.

That it prepends $PWD to the path is also a problem if the
current working directory has been renamed, but most shells do
that without -P.

It's better in that case with cd -P or with chaselinks:

$ strace -fe getcwd,readlink,chdir,fchdir zsh -c 'cd -P link'
readlink("/proc/self/fd/0", "/dev/pts/4", 4095) = 10
chdir("/home/chazelas/link")            = 0
readlink("/home", 0x7ffe6ba34f00, 4096) = -1 EINVAL (Invalid argument)
readlink("/home/chazelas", 0x7ffe6ba34f00, 4096) = -1 EINVAL (Invalid argument)
readlink("/home/chazelas/link", "/proc/self/cwd/..", 4096) = 17
readlink("/proc", 0x7ffe6ba2fe70, 4096) = -1 EINVAL (Invalid argument)
readlink("/proc/self", "1000438", 4096) = 7
readlink("/proc/1000438", 0x7ffe6ba2ade0, 4096) = -1 EINVAL (Invalid argument)
readlink("/proc/1000438/cwd", "/home", 4096) = 5
readlink("/home", 0x7ffe6ba2ade0, 4096) = -1 EINVAL (Invalid argument)
chdir("..")                             = 0
chdir("/home")                          = 0
+++ exited with 0 +++
~$ strace -fe getcwd,readlink,chdir,fchdir zsh -o chaselinks -c 'cd link'
readlink("/proc/self/fd/0", "/dev/pts/4", 4095) = 10
readlink("/home", 0x7ffdfc3e0f40, 4096) = -1 EINVAL (Invalid argument)
readlink("/home/chazelas", 0x7ffdfc3e0f40, 4096) = -1 EINVAL (Invalid argument)
chdir("/home/chazelas/link")            = 0
readlink("/home", 0x7ffdfc3df960, 4096) = -1 EINVAL (Invalid argument)
readlink("/home/chazelas", 0x7ffdfc3df960, 4096) = -1 EINVAL (Invalid argument)
readlink("/home/chazelas/link", "/proc/self/cwd/..", 4096) = 17
readlink("/proc", 0x7ffdfc3da8d0, 4096) = -1 EINVAL (Invalid argument)
readlink("/proc/self", "1002598", 4096) = 7
readlink("/proc/1002598", 0x7ffdfc3d5840, 4096) = -1 EINVAL (Invalid argument)
readlink("/proc/1002598/cwd", "/home", 4096) = 5
readlink("/home", 0x7ffdfc3d5840, 4096) = -1 EINVAL (Invalid argument)
chdir("..")                             = 0
chdir("/home")                          = 0
+++ exited with 0 +++

But that sounds a bit overkill and racy.

In scripts, you usually want your cd's to do plain chdir()s but
there are many things that get in the way:

- the need for -P to avoid the logical traversal
- the need to -- as usual for avoid problems with dirnames
  starting with -
- CDPATH (it is inherited from the environment but at least when
  not in POSIX mode, that doesn't take precedence over actual
  relative path).
- The "-" string that is taken as $OLDPWD
- Also in zsh, the -n +n ones.
- and then there's that special fancy chasing of symlinks

So, to do an actual chdir, we need something like:

chdir() {
  case $1 in
    (/*) cd -P "$1";;
    ('') print -u2 "not sure out to chdir to an empty string";;
    (*) cd -P "./$1";;
  esac
}

Which addresses the first 5 points, but not the 6th.

It would be nice if we could just do for instance cd -r -- $dir
which would just a do chdir($dir) and set $PWD to getcwd() if
successful.

(or have chdir (which atm exits as a builtin for tcsh junkies I
suppose) do that and not take any option).

What do you think?

-- 
Stephane




Messages sorted by: Reverse Date, Date, Thread, Author