On GNU/Hurd I see the following: FAIL: test-fdutimensat ====================== test-utimens.h:80: assertion 'func (BASE "file", ts) == -1' failed FAIL test-fdutimensat (exit status: 134) FAIL: test-futimens =================== test-futimens.h:106: assertion 'func (fd, ts) == -1' failed FAIL test-futimens (exit status: 134)
This is similar to the utimensat issue [1]. Adding a similar configure check for out-of-range tv_nsec values for futimens fixes both tests. While there, I adjusted the configure check to return a bit mask instead of exiting early. Also reported the bug and mentioned it in the docs [2]. Looking at the code, NetBSD has a similar situation so I documented that too [3]. Collin [1] https://lists.gnu.org/archive/html/bug-gnulib/2025-03/msg00058.html [2] https://sourceware.org/bugzilla/show_bug.cgi?id=32803 [3] https://lists.gnu.org/archive/html/bug-gnulib/2024-09/msg00120.html
>From 23a3940f61f46e84067c4b472920e1c7d34459c2 Mon Sep 17 00:00:00 2001 From: Collin Funk <collin.fu...@gmail.com> Date: Tue, 18 Mar 2025 21:50:00 -0700 Subject: [PATCH] futimens: Work around a GNU/Hurd bug. * m4/futimens.m4 (gl_FUNC_FUTIMENS): Check if futimens validates the tv_nsec values of the timespec argument. Set bits in a return value instead of exiting early. * doc/posix-functions/futimens.texi (futimens): Mention the GNU/Hurd bug. Mention the same bug occurs on NetBSD 10. --- ChangeLog | 7 ++++++ doc/posix-functions/futimens.texi | 5 ++++ m4/futimens.m4 | 39 ++++++++++++++++++++++++------- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index a0a8763da1..eb51b0f33a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2025-03-18 Collin Funk <collin.fu...@gmail.com> + futimens: Work around a GNU/Hurd bug. + * m4/futimens.m4 (gl_FUNC_FUTIMENS): Check if futimens validates the + tv_nsec values of the timespec argument. Set bits in a return value + instead of exiting early. + * doc/posix-functions/futimens.texi (futimens): Mention the GNU/Hurd + bug. Mention the same bug occurs on NetBSD 10. + mountlist: Add tests. * modules/mountlist-tests: New file. * tests/test-mountlist.c: New file. diff --git a/doc/posix-functions/futimens.texi b/doc/posix-functions/futimens.texi index 74c3301433..61520789c1 100644 --- a/doc/posix-functions/futimens.texi +++ b/doc/posix-functions/futimens.texi @@ -31,6 +31,11 @@ @node futimens Passing @code{AT_FDCWD} as the fd argument does not properly fail with @code{EBADF} on some systems: glibc 2.11, musl libc, Solaris 11. +@item +Out-of-range values of @code{tv_nsec} do not lead to a failure on some +platforms: +@c https://sourceware.org/bugzilla/show_bug.cgi?id=32803 +NetBSD 10.0, GNU/Hurd. @end itemize Portability problems not fixed by Gnulib: diff --git a/m4/futimens.m4 b/m4/futimens.m4 index fe89fdffa1..7252dd66d1 100644 --- a/m4/futimens.m4 +++ b/m4/futimens.m4 @@ -1,5 +1,5 @@ # futimens.m4 -# serial 11 +# serial 12 dnl Copyright (C) 2009-2025 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -32,22 +32,45 @@ AC_DEFUN([gl_FUNC_FUTIMENS] ]GL_MDA_DEFINES], [[struct timespec ts[2]; int fd = creat ("conftest.file", 0600); + int result = 0; struct stat st; - if (fd < 0) return 1; + if (fd < 0) + return 1; ts[0].tv_sec = 1; ts[0].tv_nsec = UTIME_OMIT; ts[1].tv_sec = 1; ts[1].tv_nsec = UTIME_NOW; errno = 0; - if (futimens (AT_FDCWD, NULL) == 0) return 2; - if (errno != EBADF) return 3; - if (futimens (fd, ts)) return 4; + if (futimens (AT_FDCWD, NULL) == 0 || errno != EBADF) + result |= 2; + if (futimens (fd, ts)) + result |= 4; sleep (1); ts[0].tv_nsec = UTIME_NOW; ts[1].tv_nsec = UTIME_OMIT; - if (futimens (fd, ts)) return 5; - if (fstat (fd, &st)) return 6; - if (st.st_ctime < st.st_atime) return 7; + if (futimens (fd, ts)) + result |= 8; + if (fstat (fd, &st)) + result |= 16; + if (st.st_ctime < st.st_atime) + result |= 32; + enum + { + BILLION = 1000 * 1000 * 1000, + /* Bogus positive and negative tv_nsec values closest to valid + range, but without colliding with UTIME_NOW or UTIME_OMIT. */ + UTIME_BOGUS_POS = BILLION + ((UTIME_NOW == BILLION || UTIME_OMIT == BILLION) + ? (1 + (UTIME_NOW == BILLION + 1) + + (UTIME_OMIT == BILLION + 1)) + : 0) + }; + ts[0].tv_sec = 1; + ts[0].tv_nsec = UTIME_BOGUS_POS; + ts[1].tv_sec = 1; + ts[1].tv_nsec = 0; + if (futimens (fd, ts) == 0) + result |= 64; + return result; ]])], [gl_cv_func_futimens_works=yes], [gl_cv_func_futimens_works=no], -- 2.48.1