Zach van Rijn wrote in <https://lists.gnu.org/archive/html/bug-gnulib/2023-04/msg00072.html>: > I am investigating a possible regression in gnulib that manifests > as a behavioral change in coreutils `pwd` on some Linux platforms. > > Comparing coreutils 9.1 and 9.2 release tarballs, freshly built: > > $ x=$(pwd) && (cd //tmp && for k in 9.1 9.2; do echo -n $k:\ && > ${x}/coreutils-$k/src/pwd; done) > 9.1: /tmp > 9.2: //tmp
The reproducer is not only $ (cd //bin && /coreutils/src/pwd) but also $ (cd /bin && /coreutils/src/pwd) Using /bin instead of /tmp is a better reproducer, because e.g. on Alpine Linux /tmp is a mount point, and the getcwd code treats mount points specially (see lib/getcwd.c line 310). > The coreutils commit that updated gnulib is: > > d42e4e9191abb818fc0e28507085a3945eed1477 > > The gnulib commit that caused this behavioral change is: > > 356a414e8c15ef3f8cc7b7157427c8ce9a9f7c1b > > More information: > > https://git.adelielinux.org/adelie/packages/-/issues/987 I reproduce it only on Adelie Linux, not on Alpine Linux or Ubuntu, for example, because in config.h: * On Adelie Linux /* #undef HAVE_MINIMALLY_WORKING_GETCWD */ /* #undef HAVE_PARTLY_WORKING_GETCWD */ * On Ubuntu #define HAVE_MINIMALLY_WORKING_GETCWD 1 /* #undef HAVE_PARTLY_WORKING_GETCWD */ * On Alpine Linux #define HAVE_MINIMALLY_WORKING_GETCWD 1 #define HAVE_PARTLY_WORKING_GETCWD 1 Also, it is reproducible only if /proc is mounted. An strace log looks like this: execve("/home/bruno/coreutils-9.5/src/pwd", ["/home/bruno/coreutils-9.5/src/pw"...], 0x7ffdf3982670 /* 19 vars */) = 0 arch_prctl(ARCH_SET_FS, 0x7f1946be2a88) = 0 set_tid_address(0x7f1946be3034) = 19425 brk(NULL) = 0x55c1f29d7000 brk(0x55c1f29d9000) = 0x55c1f29d9000 mmap(0x55c1f29d7000, 4096, PROT_NONE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x55c1f29d7000 mprotect(0x7f1946bdf000, 4096, PROT_READ) = 0 mprotect(0x55c1f28d9000, 4096, PROT_READ) = 0 mmap(NULL, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1946b29000 lstat(".", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0 lstat("/", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 openat(AT_FDCWD, "..", O_RDONLY|O_LARGEFILE) = 3 fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 fcntl(3, F_GETFL) = 0x8000 (flags O_RDONLY|O_LARGEFILE) mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1946b27000 fcntl(3, F_SETFD, FD_CLOEXEC) = 0 getdents64(3, 0x7f1946b27048 /* 21 entries */, 2048) = 520 newfstatat(3, "bin", {st_mode=S_IFDIR|0755, st_size=12288, ...}, AT_SYMLINK_NOFOLLOW) = 0 readlink("/proc/self/fd/3", "/", 4096) = 1 close(3) = 0 munmap(0x7f1946b27000, 8192) = 0 munmap(0x7f1946b29000, 16384) = 0 ioctl(1, TIOCGWINSZ, {ws_row=37, ws_col=100, ws_xpixel=0, ws_ypixel=400}) = 0 writev(1, [{iov_base="//bin", iov_len=5}, {iov_base="\n", iov_len=1}], 2) = 6 close(1) = 0 close(2) = 0 exit_group(0) = ? +++ exited with 0 +++ So, the readlink on the root directory returns "/", not "//". The double slash comes from not-so-careful string concatenation. This patch fixes it. 2024-12-31 Bruno Haible <br...@clisp.org> getcwd: Return "/bin" instead of "//bin" on Adélie Linux. Reported by Zach van Rijn <m...@zv.io> in <https://lists.gnu.org/archive/html/bug-gnulib/2023-04/msg00072.html> and <https://git.adelielinux.org/adelie/packages/-/issues/987>. * lib/getcwd.c (__getcwd_generic): Remove a trailing slash from the result of readlink(). diff --git a/lib/getcwd.c b/lib/getcwd.c index 214950a144..d637b4e576 100644 --- a/lib/getcwd.c +++ b/lib/getcwd.c @@ -478,6 +478,12 @@ __getcwd_generic (char *buf, size_t size) } else { + /* *dirp is already a '/' (see above). Therefore if the directory + ends in a slash, we can remove that slash. This happens in + particular if the directory is "/". */ + if (linklen > 0 && linkbuf[linklen - 1] == '/') + linklen--; + dirroom = dirp - dir; if (dirroom < linklen) {