On 10/21/23 00:05, Bart Schaefer wrote:
On Fri, Oct 20, 2023 at 8:18 PM Kyle Laker <kyle@laker.email> wrote:When you run `pwd -P`, zsh invokes the getcwd() system call and prints whatever it returns. That's literally all it does. So, although I don't have BTRFS to test with, this looks from here like a problem with getcwd() internally changing the process current directory to the root when crossing a BTRFS link. That would be invisible to $PWD and therefore to the pwd command (without -P).
Thanks for the context! So it seems like the issue is in the non-getcwd() zgetdir() code path. Checking against master, this issue is no longer present with a default configure after workers/50287 enabled using getcwd() by default just after the 5.9 release. getcwd() seems to handle this case correctly.
For situations where getcwd() isn't used, the actual errant `cd`ing happens at the end of the `while` loop in zgetdir(). This continuously calls `chdir("..")`. Eventually, this puts us at `/`. Typically, the call to `zchdir(buf + pos)` would take us back to the directory we started in; however, because ZSH determined the path was `/home/kyle.homedir` (using the homed image path) instead of `/home/kyle` (the actual mounted home directory), that fails. The `.homedir` folder is owned by nobody:nobody so when zchdir() calls chdir(3) the latter fails with an EACCES error. This leaves the process in `/`, where it was put by zgetdir() but without any of the other environment variables updated.
I'm not sure how these btrfs homedir mounts can be determined in situations like this (or how valuable it would be since nearly everyone with btrfs probably has a working getcwd(3)). But perhaps if the final zchdir() fails, zgetdir() could chdir(3) back to the original path rather than the resolved path?