I'm testing a POSIX testdir of gnulib on a 9p file system [1], which serves as a shared directory between the host and the guest VM. 'mount' reports this line: /dev/share on /share type 9p (rw,sync,dirsync,relatime,access=client,trans=virtio) I see several test failures:
FAIL: test-fchdir FAIL: test-fstatat FAIL: test-getcwd-lgpl FAIL: test-getcwd.sh FAIL: test-linkat FAIL: test-renameat FAIL: test-renameatu FAIL: test-stat FAIL: test-statat The cause is that the configure test in getcwd-path-max.m4 has experienced an unexpected errno value: ... mkdirat(AT_FDCWD, "confdir3", 0700) = 0 chdir("confdir3") = 0 mkdirat(AT_FDCWD, "confdir3", 0700) = -1 EINVAL (Invalid argument) unlinkat(AT_FDCWD, "confdir3", AT_REMOVEDIR) = -1 ENOENT (No such file or directory) chdir("..") = 0 ... leading to an exit code of 20. As a consequence, the normal glibc / system call getcwd(), which would succeed: getcwd("/share/home/bruno", 4096) = 18 is overridden by a gnulib getcwd(), which fails: newfstatat(AT_FDCWD, ".", {st_mode=S_IFREG|071600022, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0 newfstatat(AT_FDCWD, "/", {st_mode=002, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0 openat(AT_FDCWD, "..", O_RDONLY|O_LARGEFILE) = 3 fstat(3, {st_mode=S_IFREG|071600015, st_size=0, ...}) = 0 fstat(3, {st_mode=S_IFREG|071600015, st_size=0, ...}) = 0 fcntl(3, F_GETFL) = 0x8000 (flags O_RDONLY|O_LARGEFILE) fcntl(3, F_SETFD, FD_CLOEXEC) = 0 getdents64(3, 0x15190, 32768) = -1 EPROTO (Protocol error) close(3) = 0 It's not required to investigate the precise cause of this EPROTO error; we know that on Linux the getcwd() system call is good and that therefore the gnulib getcwd() override is suboptimal. This patch fixes the issue. [1] https://www.kernel.org/doc/Documentation/filesystems/9p.txt 2019-01-13 Bruno Haible <br...@clisp.org> getcwd: Fix test failure when building on a Linux 9p file system. * m4/getcwd-path-max.m4 (gl_FUNC_GETCWD_PATH_MAX): On Linux, treat error EINVAL from mkdir like ENAMETOOLONG. * tests/test-getcwd.c (test_long_name): Likewise. diff --git a/m4/getcwd-path-max.m4 b/m4/getcwd-path-max.m4 index 2cefc00..0ae3e1e 100644 --- a/m4/getcwd-path-max.m4 +++ b/m4/getcwd-path-max.m4 @@ -1,4 +1,4 @@ -# serial 21 +# serial 22 # Check for several getcwd bugs with long file names. # If so, arrange to compile the wrapper function. @@ -111,12 +111,20 @@ main () /* If mkdir or chdir fails, it could be that this system cannot create any file with an absolute name longer than PATH_MAX, such as cygwin. If so, leave fail as 0, because the current working directory can't - be too long for getcwd if it can't even be created. For other - errors, be pessimistic and consider that as a failure, too. */ + be too long for getcwd if it can't even be created. On Linux with + the 9p file system, mkdir fails with error EINVAL when cwd_len gets + too long; ignore this failure because the getcwd() system call + produces good results whereas the gnulib substitute calls getdents64 + which fails with error EPROTO. + For other errors, be pessimistic and consider that as a failure, + too. */ if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0) { if (! (errno == ERANGE || is_ENAMETOOLONG (errno))) - fail = 20; + #ifdef __linux__ + if (! (errno == EINVAL)) + #endif + fail = 20; break; } diff --git a/tests/test-getcwd.c b/tests/test-getcwd.c index 31c9037..b5f8155 100644 --- a/tests/test-getcwd.c +++ b/tests/test-getcwd.c @@ -166,12 +166,20 @@ test_long_name (void) /* If mkdir or chdir fails, it could be that this system cannot create any file with an absolute name longer than PATH_MAX, such as cygwin. If so, leave fail as 0, because the current working directory can't - be too long for getcwd if it can't even be created. For other - errors, be pessimistic and consider that as a failure, too. */ + be too long for getcwd if it can't even be created. On Linux with + the 9p file system, mkdir fails with error EINVAL when cwd_len gets + too long; ignore this failure because the getcwd() system call + produces good results whereas the gnulib substitute calls getdents64 + which fails with error EPROTO. + For other errors, be pessimistic and consider that as a failure, + too. */ if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0) { if (! (errno == ERANGE || errno == ENAMETOOLONG || errno == ENOENT)) - fail = 2; + #ifdef __linux__ + if (! (errno == EINVAL)) + #endif + fail = 2; break; }