2024-12-31 I wrote:
> 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

Why is HAVE_MINIMALLY_WORKING_GETCWD not defined on Adélie Linux?
The test program (attached) fails with code 21. After

  c = getcwd (buf, PATH_MAX);

we expect errno to be ERANGE or ENAMETOOLONG, but it is ENOMEM instead.

This is caused by an Adélie Linux specific change [1].
A change that could have been avoided by reading/interpreting POSIX [2]
properly. Or simply by trusting Rich Felker's work in upstream musl libc.

I'm glad that Gnulib shields coreutils from this non-conforming behaviour.

Bruno

[1] 
https://git.adelielinux.org/adelie/musl/-/blob/posix-compliance/src/unistd/getcwd.c?ref_type=heads
[2] https://pubs.opengroup.org/onlinepubs/9799919799/functions/getcwd.html
/* confdefs.h */
#define PACKAGE_NAME "GNU coreutils"
#define PACKAGE_TARNAME "coreutils"
#define PACKAGE_VERSION "snapshot"
#define PACKAGE_STRING "GNU coreutils snapshot"
#define PACKAGE_BUGREPORT "bug-coreut...@gnu.org"
#define PACKAGE_URL "https://www.gnu.org/software/coreutils/";
#define PACKAGE "coreutils"
#define VERSION "snapshot"
#define HAVE_STDIO_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRING_H 1
#define HAVE_INTTYPES_H 1
#define HAVE_STDINT_H 1
#define HAVE_STRINGS_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_UNISTD_H 1
#define HAVE_WCHAR_H 1
#define HAVE_ARPA_INET_H 1
#define HAVE_FEATURES_H 1
#define HAVE_SYS_SOCKET_H 1
#define HAVE_STDBOOL_H 1
#define HAVE_BYTESWAP_H 1
#define HAVE_UCHAR_H 1
#define HAVE_SYS_PARAM_H 1
#define HAVE_DIRENT_H 1
#define HAVE_ENDIAN_H 1
#define HAVE_FNMATCH_H 1
#define HAVE_STDIO_EXT_H 1
#define HAVE_SYS_VFS_H 1
#define HAVE_NETDB_H 1
#define HAVE_NETINET_IN_H 1
#define HAVE_GETOPT_H 1
#define HAVE_SYS_TIME_H 1
#define HAVE_GRP_H 1
#define HAVE_THREADS_H 1
#define HAVE_ICONV_H 1
#define HAVE_LIMITS_H 1
#define HAVE_WCTYPE_H 1
#define HAVE_LANGINFO_H 1
#define HAVE_MATH_H 1
#define HAVE_SYS_MMAN_H 1
#define HAVE_SYS_STATVFS_H 1
#define HAVE_SYS_SELECT_H 1
#define HAVE_PTHREAD_H 1
#define HAVE_MALLOC_H 1
#define HAVE_SYS_IOCTL_H 1
#define HAVE_SYS_RANDOM_H 1
#define HAVE_SYS_RESOURCE_H 1
#define HAVE_SYS_UIO_H 1
#define HAVE_SYS_UTSNAME_H 1
#define HAVE_SYS_WAIT_H 1
#define HAVE_TERMIOS_H 1
#define HAVE_UTIME_H 1
#define HAVE_SEMAPHORE_H 1
#define HAVE_SYS_UN_H 1
#define HAVE_PATHS_H 1
#define HAVE_STROPTS_H 1
#define HAVE_SYS_MTIO_H 1
#define HAVE_SYSLOG_H 1
#define HAVE_PWD_H 1
#define STDC_HEADERS 1
#define _ALL_SOURCE 1
#define _DARWIN_C_SOURCE 1
#define _GNU_SOURCE 1
#define _HPUX_ALT_XOPEN_SOCKET_API 1
#define _NETBSD_SOURCE 1
#define _OPENBSD_SOURCE 1
#define _POSIX_PTHREAD_SEMANTICS 1
#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
#define __STDC_WANT_IEC_60559_BFP_EXT__ 1
#define __STDC_WANT_IEC_60559_DFP_EXT__ 1
#define __STDC_WANT_IEC_60559_EXT__ 1
#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
#define __STDC_WANT_LIB_EXT2__ 1
#define __STDC_WANT_MATH_SPEC_FUNCS__ 1
#define _TANDEM_SOURCE 1
#define __EXTENSIONS__ 1
#define _LINUX_SOURCE_COMPAT 1
#define __USE_MINGW_ANSI_STDIO 1
#define HAVE_LSTAT 1
#define HAVE_FCHMOD 1
#define HAVE_PATHCONF 1
#define HAVE_BTOWC 1
#define HAVE_MBRTOWC 1
#define HAVE_MBSINIT 1
#define HAVE_REALPATH 1
#define HAVE_CHOWN 1
#define HAVE_FCHOWN 1
#define HAVE_FCHDIR 1
#define HAVE_EXPLICIT_BZERO 1
#define HAVE_POSIX_FADVISE 1
#define HAVE_FCHMODAT 1
#define HAVE_LCHMOD 1
#define HAVE_FCNTL 1
#define HAVE_SYMLINK 1
#define HAVE_FDOPENDIR 1
#define HAVE_LISTXATTR 1
#define HAVE_FNMATCH 1
#define HAVE_MBSRTOWCS 1
#define HAVE_FPURGE 1
#define HAVE___FREADPTR 1
#define HAVE___FREADPTRINC 1
#define HAVE_FSTATAT 1
#define HAVE_FSYNC 1
#define HAVE_OPENAT 1
#define HAVE_FSTATFS 1
#define HAVE_GETDTABLESIZE 1
#define HAVE_GETLOGIN 1
#define HAVE_FLOCKFILE 1
#define HAVE_FUNLOCKFILE 1
#define HAVE_GETTIMEOFDAY 1
#define HAVE_ISBLANK 1
#define HAVE_ISWCNTRL 1
#define HAVE_LINK 1
#define HAVE_READLINK 1
#define HAVE_MBRLEN 1
#define HAVE_ISASCII 1
#define HAVE_MPROTECT 1
#define HAVE_GETGROUPLIST 1
#define HAVE_MKDIRAT 1
#define HAVE_MKNOD 1
#define HAVE_MKSTEMP 1
#define HAVE_PIPE 1
#define HAVE_PSELECT 1
#define HAVE_PTHREAD_SIGMASK 1
#define HAVE_QSORT_R 1
#define HAVE_UTMPNAME 1
#define HAVE_UTMPXNAME 1
#define HAVE_ISWCTYPE 1
#define HAVE_RENAMEAT 1
#define HAVE_FPATHCONF 1
#define HAVE_SECURE_GETENV 1
#define HAVE_GETUID 1
#define HAVE_GETEUID 1
#define HAVE_GETGID 1
#define HAVE_GETEGID 1
#define HAVE_SETENV 1
#define HAVE_SETTIMEOFDAY 1
#define HAVE_STIME 1
#define HAVE_SIGACTION 1
#define HAVE_SIGALTSTACK 1
#define HAVE_SIGINTERRUPT 1
#define HAVE_SNPRINTF 1
#define HAVE___XPG_STRERROR_R 1
#define HAVE_STRTOIMAX 1
#define HAVE_STRTOLD 1
#define HAVE_STRTOUMAX 1
#define HAVE_LOCALTIME_R 1
#define HAVE_UNLINKAT 1
#define HAVE_WCRTOMB 1
#define HAVE_WCWIDTH 1
#define HAVE_PAUSE 1
#define HAVE_GETRUSAGE 1
#define HAVE_SLEEP 1
#define HAVE_SHUTDOWN 1
#define HAVE_USLEEP 1
#define HAVE_WCTOB 1
#define HAVE_NL_LANGINFO 1
#define HAVE_SETITIMER 1
#define HAVE_SETRLIMIT 1
#define HAVE_PRCTL 1
#define HAVE_ENDGRENT 1
#define HAVE_ENDPWENT 1
#define HAVE_FALLOCATE 1
#define HAVE_SETGROUPS 1
#define HAVE_SETHOSTNAME 1
#define HAVE_SYNC 1
#define HAVE_SYNCFS 1
#define HAVE_SYSINFO 1
#define HAVE_TCGETPGRP 1
#define HAVE_FORK 1
#define HAVE_VFORK 1
#define USE_ACL 0
#define HAVE_ALLOCA_H 1
#define HAVE_ALLOCA 1
#define D_INO_IN_DIRENT 1
#define HAVE_LONG_FILE_NAMES 1
#define restrict __restrict__
#define HAVE_WINT_T 1
#define HAVE_LANGINFO_CODESET 1
#define HAVE_USELOCALE 1
#define HAVE_WORKING_USELOCALE 1
#define BITSIZEOF_WCHAR_T 32
#define HAVE_MBSTATE_T 1
#define HAVE_WORKING_MBRTOC32 1
#define HAVE_WORKING_C32RTOMB 1
#define HAVE_MALLOC_PTRDIFF 1
#define HAVE_MALLOC_POSIX 1
#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
#define FUNC_REALPATH_WORKS 1
#define HAVE_UNISTD_H 1
#define HAVE_CHOWN 1
#define GL_CRC_SLICE_BY_8 1
#define GL_CRC_X86_64_PCLMUL 1
#define HAVE_SHUTDOWN 1
#define HAVE_STRUCT_SOCKADDR_STORAGE 1
#define HAVE_SA_FAMILY_T 1
#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1
#define USE_LINUX_CRYPTO_API 0
#define HAVE_ENVIRON_DECL 1
#define HAVE_DECL_STRERROR_R 1
#define HAVE_STRERROR_R 1
#define GETGROUPS_T gid_t
#define HAVE_DECL_FCHDIR 1
#define FUNC_FFLUSH_STDIN 1
#define HAVE_WORKING_O_NOATIME 1
#define HAVE_WORKING_O_NOFOLLOW 1
#define PROMOTED_MODE_T mode_t
#define HAVE_DECL_FDATASYNC 1
#define USE_SELINUX_SELINUX_H 0
#define HAVE_DECL_STRMODE 0
#define HAVE_MEMPCPY 1
#define HAVE_DECL_ALARM 1
#define _USE_STD_STAT 1
#define HAVE_DECL_FSEEKO 1
#define FUNC_FFLUSH_STDIN 1
#define HAVE_DECL_FTELLO 1
#define HAVE_GETHOSTBYNAME 1
#define HAVE_GETSERVBYNAME 1
#define HAVE_DECL_INET_NTOP 1
#define HAVE_IPV4 1
#define HAVE_IPV6 1
#define HAVE_DECL_GETCWD 1
#define HAVE_DECL_GETDELIM 1
#define HAVE_DECL_GETDTABLESIZE 1
#define HAVE_DECL_GETLINE 1
#define HAVE_DECL_GETLOGIN 1
#define HAVE_GETOPT_H 1
#define HAVE_GETOPT_LONG_ONLY 1
#define HAVE_PTHREAD_API 1
#define SETLOCALE_NULL_ALL_MTSAFE 0
#define SETLOCALE_NULL_ONE_MTSAFE 1
#define HAVE_WEAK_SYMBOLS 1
#define HAVE_ICONV 1
#define ICONV_CONST 
#define HAVE_LONG_LONG_INT 1
#define HAVE_UNSIGNED_LONG_LONG_INT 1
#define DBL_EXPBIT0_WORD 1
#define DBL_EXPBIT0_BIT 20
#define FLT_EXPBIT0_WORD 0
#define FLT_EXPBIT0_BIT 23
#define LDBL_EXPBIT0_WORD 2
#define LDBL_EXPBIT0_BIT 0
#define HAVE_TOWLOWER 1
#define HAVE_LC_MESSAGES 1
#define HAVE_USELOCALE 1
#define HAVE_WORKING_USELOCALE 1
#define HAVE_GOOD_USELOCALE 1
#define HAVE_WEAK_SYMBOLS 1
#define USE_POSIX_THREADS 1
#define USE_POSIX_THREADS_WEAK 1
#define HAVE_MALLOC_0_NONNULL 1
#define MUSL_LIBC 1
#define HAVE_MAP_ANONYMOUS 1
#define HAVE_DECL_MEMRCHR 1
#define HAVE_MINMAX_IN_SYS_PARAM_H 1
#define TIME_T_IS_SIGNED 1
#define HAVE_STRUCT_TM_TM_GMTOFF 1
#define HAVE_STRUCT_TM_TM_ZONE 1
#define HAVE_TM_GMTOFF 1
#define HAVE_COMPOUND_LITERALS 1
#define HAVE_PTHREAD_T 1
#define HAVE_PTHREAD_SPINLOCK_T 1
#define HAVE_DECL__PUTENV 0
#define HAVE_SIGSET_T 1
#define HAVE_DECL_SYSINFO 1
#define HAVE_SCHED_H 1
#define HAVE_DECL_SETENV 1
#define HAVE_SEARCH_H 1
#define HAVE_TSEARCH 1
#define HAVE_DECL_SNPRINTF 1
#define HAVE_DECL_FCLOSEALL 0
#define HAVE_DECL_GETW 1
#define HAVE_DECL_PUTW 1
#define HAVE_DECL_ECVT 1
#define HAVE_DECL_FCVT 1
#define HAVE_DECL_GCVT 1
#define HAVE_DECL_STRDUP 1
#define HAVE_STRERROR_R 1
#define HAVE_DECL_STRNLEN 1
#define HAVE_DECL_STRSIGNAL 1
#define HAVE_DECL_STRTOIMAX 1
#define HAVE_DECL_STRTOUMAX 1
#define HAVE_STRUCT_UTSNAME 1
#define HAVE_DECL_EXECVPE 1
#define HAVE_DECL_CLEARERR_UNLOCKED 1
#define HAVE_DECL_FEOF_UNLOCKED 1
#define HAVE_DECL_FERROR_UNLOCKED 1
#define HAVE_DECL_FFLUSH_UNLOCKED 1
#define HAVE_DECL_FGETS_UNLOCKED 1
#define HAVE_DECL_FPUTC_UNLOCKED 1
#define HAVE_DECL_FPUTS_UNLOCKED 1
#define HAVE_DECL_FREAD_UNLOCKED 1
#define HAVE_DECL_FWRITE_UNLOCKED 1
#define HAVE_DECL_GETC_UNLOCKED 1
#define HAVE_DECL_GETCHAR_UNLOCKED 1
#define HAVE_DECL_PUTC_UNLOCKED 1
#define HAVE_DECL_PUTCHAR_UNLOCKED 1
#define HAVE_DECL_UNSETENV 1
#define HAVE_WORKING_UTIMES 1
#define HAVE_INTTYPES_H_WITH_UINTMAX 1
#define HAVE_STDINT_H_WITH_UINTMAX 1
#define HAVE_INTMAX_T 1
#define HAVE_WCSLEN 1
#define HAVE_SNPRINTF 1
#define HAVE_STRNLEN 1
#define HAVE_WCRTOMB 1
#define HAVE_DECL__SNPRINTF 0
#define HAVE_SNPRINTF_RETVAL_C99 1
#define HAVE_SNPRINTF_TRUNCATION_C99 1
#define CHECK_PRINTF_SAFE 1
#define HAVE_VASPRINTF 1
#define HAVE_DECL_WCSDUP 1
#define HAVE_DECL_INITSTATE 1
#define HAVE_DECL_SETSTATE 1
#define GNULIB_TEST_ACCESS 1
#define HAVE_POSIX_MEMALIGN 1
#define HAVE_ALLOCA 1
#define GNULIB_AREADLINKAT 1
#define GNULIB_AREADLINKAT_WITH_SIZE 1
#define GNULIB_TEST_BTOC32 1
#define GNULIB_TEST_BTOWC 1
#define HAVE___BUILTIN_EXPECT 1
#define HAVE_NL_LANGINFO 1
#define HAVE_STRTOD_L 1
#define HAVE_NL_LANGINFO 1
#define HAVE_STRTOLD_L 1
#define GNULIB_TEST_C32_APPLY_TYPE_TEST 1
#define GNULIB_TEST_C32_GET_TYPE_TEST 1
#define GNULIB_TEST_C32ISALNUM 1
#define GNULIB_TEST_C32ISALPHA 1
#define GNULIB_TEST_C32ISBLANK 1
#define GNULIB_TEST_C32ISCNTRL 1
#define GNULIB_TEST_C32ISDIGIT 1
#define GNULIB_TEST_C32ISGRAPH 1
#define GNULIB_TEST_C32ISLOWER 1
#define GNULIB_TEST_C32ISPRINT 1
#define GNULIB_TEST_C32ISPUNCT 1
#define GNULIB_TEST_C32ISSPACE 1
#define GNULIB_TEST_C32ISUPPER 1
#define GNULIB_TEST_C32ISXDIGIT 1
#define GNULIB_TEST_C32TOLOWER 1
#define GNULIB_TEST_C32WIDTH 1
#define GNULIB_TEST_CALLOC_GNU 1
#define GNULIB_TEST_CALLOC_POSIX 1
#define HAVE_FACCESSAT 1
#define GNULIB_CANONICALIZE 1
#define GNULIB_TEST_CANONICALIZE 1
#define GNULIB_TEST_CANONICALIZE_FILE_NAME 1
#define HAVE_READLINKAT 1
#define GNULIB_TEST_CHDIR 1
#define GNULIB_TEST_CHMOD 1
#define GNULIB_CHMODAT 1
#define GNULIB_TEST_CHOWN 1
#define GNULIB_CHOWNAT 1
#define HAVE_CLOCK_GETRES 1
#define HAVE_CLOCK_GETTIME 1
#define HAVE_CLOCK_SETTIME 1
#define GNULIB_TEST_CLOEXEC 1
#define GNULIB_TEST_CLOSE 1
#define GNULIB_CLOSE 1
#define GNULIB_CLOSE_STREAM 1
#define HAVE_CLOSEDIR 1
#define GNULIB_TEST_CLOSEDIR 1
#define HAVE_COPY_FILE_RANGE 1
#define HAVE_COPY_FILE_RANGE 1
#define GNULIB_TEST_COPY_FILE_RANGE 1
#define D_INO_IN_DIRENT 1
#define HAVE_STRUCT_DIRENT_D_TYPE 1
#define HAVE_DIRFD 1
#define HAVE_DECL_DIRFD 1
#define GNULIB_TEST_DIRFD 1
#define GNULIB_DIRNAME 1
#define GNULIB_TEST_DUP 1
#define GNULIB_TEST_DUP2 1
#define GNULIB_TEST_ENVIRON 1
#define HAVE_EUIDACCESS 1
#define GNULIB_TEST_EUIDACCESS 1
#define GNULIB_TEST_EXPLICIT_BZERO 1
#define HAVE_FACCESSAT 1
#define GNULIB_FACCESSAT 1
#define GNULIB_TEST_FACCESSAT 1
#define GNULIB_TEST_FCHDIR 1
#define GNULIB_TEST_FCHMODAT 1
#define GNULIB_TEST_FCHOWNAT 1
#define GNULIB_TEST_FCLOSE 1
#define GNULIB_TEST_FCNTL 1
#define GNULIB_FCNTL_SAFER 1
#define GNULIB_FD_SAFER_FLAG 1
#define HAVE_FDATASYNC 1
#define GNULIB_TEST_FDATASYNC 1
#define GNULIB_TEST_FDOPEN 1
#define HAVE_DECL_FDOPENDIR 1
#define GNULIB_TEST_FDOPENDIR 1
#define GNULIB_FDOPENDIR 1
#define GNULIB_FDUTIMENSAT 1
#define FUNC_FFLUSH_STDIN 1
#define GNULIB_FFLUSH 1
#define GNULIB_TEST_FFLUSH 1
#define HAVE_STRUCT_STAT_ST_BLOCKS 1
#define HAVE_ST_BLOCKS 1
#define GNULIB_FILENAMECAT 1
#define HAVE_MEMPCPY 1
#define FLEXIBLE_ARRAY_MEMBER /**/
#define GNULIB_TEST_FNMATCH 1
#define GNULIB_FNMATCH_GNU 1
#define GNULIB_TEST_FOPEN 1
#define GNULIB_FOPEN_GNU 1
#define GNULIB_TEST_FOPEN_GNU 1
#define GNULIB_FOPEN_SAFER 1
#define HAVE_DECL___FPENDING 1
#define HAVE___FPURGE 1
#define HAVE_DECL_FPURGE 0
#define GNULIB_TEST_FPURGE 1
#define HAVE___FREADAHEAD 1
#define HAVE___FREADING 1
#define GNULIB_TEST_FREE_POSIX 1
#define GNULIB_TEST_FREOPEN 1
#define GNULIB_FREOPEN_SAFER 1
#define HAVE_FREXP_IN_LIBC 1
#define GNULIB_TEST_FREXP 1
#define HAVE_FREXPL_IN_LIBC 1
#define GNULIB_TEST_FREXPL 1
#define GNULIB_TEST_FSEEK 1
#define FUNC_FFLUSH_STDIN 1
#define GNULIB_TEST_FSEEKO 1
#define HAVE___FSETERR 1
#define GNULIB_TEST_FSTAT 1
#define GNULIB_FSTAT 1
#define GNULIB_TEST_FSTATAT 1
#define GNULIB_FSTATAT 1
#define HAVE_SYS_MOUNT_H 1
#define STAT_STATVFS 1
#define STAT_STATFS2_FRSIZE 1
#define HAVE_SYS_STATFS_H 1
#define GNULIB_TEST_FSYNC 1
#define GNULIB_TEST_FTELL 1
#define GNULIB_TEST_FTELLO 1
#define HAVE_STRTOF 1
#define HAVE_FTRUNCATE 1
#define GNULIB_TEST_FTRUNCATE 1
#define HAVE_STRUCT_STATFS_F_TYPE 1
#define HAVE_FUTIMENS 1
#define GNULIB_TEST_FUTIMENS 1
#define HAVE_GETADDRINFO 1
#define HAVE_DECL_GAI_STRERROR 1
#define HAVE_DECL_GAI_STRERRORA 0
#define HAVE_DECL_GETADDRINFO 1
#define HAVE_DECL_FREEADDRINFO 1
#define HAVE_DECL_GETNAMEINFO 1
#define HAVE_STRUCT_ADDRINFO 1
#define GNULIB_TEST_GETADDRINFO 1
/* end confdefs.h.  */

#include <errno.h>
#include <stdlib.h>
#if HAVE_UNISTD_H
# include <unistd.h>
#else
# include <direct.h>
#endif
#if HAVE_DECL_ALARM
# include <signal.h>
#endif
#include <string.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>


/* Arrange to define PATH_MAX, like "pathmax.h" does. */
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <limits.h>
#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
# include <sys/param.h>
#endif
#if !defined PATH_MAX && defined MAXPATHLEN
# define PATH_MAX MAXPATHLEN
#endif
#ifdef __hpux
# undef PATH_MAX
# define PATH_MAX 1024
#endif
#if defined _WIN32 && ! defined __CYGWIN__
# undef PATH_MAX
# define PATH_MAX 260
#endif


#ifndef AT_FDCWD
# define AT_FDCWD 0
#endif
#ifdef ENAMETOOLONG
# define is_ENAMETOOLONG(x) ((x) == ENAMETOOLONG)
#else
# define is_ENAMETOOLONG(x) 0
#endif

/* Use the getcwd function, not any macro.  */
#undef getcwd




#if defined _WIN32 && !defined __CYGWIN__
#define access    _access
#define chdir     _chdir
#define chmod     _chmod
#define close     _close
#define creat     _creat
#define dup       _dup
#define dup2      _dup2
#define ecvt      _ecvt
#define execl     _execl
#define execle    _execle
#define execlp    _execlp
#define execv     _execv
#define execve    _execve
#define execvp    _execvp
#define execvpe   _execvpe
#define fcloseall _fcloseall
#define fcvt      _fcvt
#define fdopen    _fdopen
#define fileno    _fileno
#define gcvt      _gcvt
#define getcwd    _getcwd
#define getpid    _getpid
#define getw      _getw
#define isatty    _isatty
#define j0        _j0
#define j1        _j1
#define jn        _jn
#define lfind     _lfind
#define lsearch   _lsearch
#define lseek     _lseek
#define memccpy   _memccpy
#define mkdir     _mkdir
#define mktemp    _mktemp
#define open      _open
#define putenv    _putenv
#define putw      _putw
#define read      _read
#define rmdir     _rmdir
#define strdup    _strdup
#define swab      _swab
#define tempnam   _tempnam
#define tzset     _tzset
#define umask     _umask
#define unlink    _unlink
#define utime     _utime
#define wcsdup    _wcsdup
#define write     _write
#define y0        _y0
#define y1        _y1
#define yn        _yn
#endif



#ifndef S_IRWXU
# define S_IRWXU 0700
#endif

/* The length of this name must be 8.  */
#define DIR_NAME "confdir3"
#define DIR_NAME_LEN 8
#define DIR_NAME_SIZE (DIR_NAME_LEN + 1)

/* The length of "../".  */
#define DOTDOTSLASH_LEN 3

/* Leftover bytes in the buffer, to work around library or OS bugs.  */
#define BUF_SLOP 20

int
main ()
{
#ifndef PATH_MAX
  /* The Hurd doesn't define this, so getcwd can't exhibit the bug --
     at least not on a local file system.  And if we were to start worrying
     about remote file systems, we'd have to enable the wrapper function
     all of the time, just to be safe.  That's not worth the cost.  */
  exit (0);
#elif ((INT_MAX / (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1)         - DIR_NAME_SIZE - BUF_SLOP)        <= PATH_MAX)
  /* FIXME: Assuming there's a system for which this is true,
     this should be done in a compile test.  */
  exit (0);
#else
  char buf[PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1)
           + DIR_NAME_SIZE + BUF_SLOP];
  char *cwd;
  size_t initial_cwd_len;
  size_t cwd_len;
  int fail;
  size_t n_chdirs;

# if HAVE_DECL_ALARM
  /* This test makes some buggy getcwd implementations take a long time, e.g.
     on NAS devices
     <https://lists.gnu.org/archive/html/bug-gnulib/2024-03/msg00444.html>
     and in sandboxed environments <https://bugs.gentoo.org/447970>.
     Give up after 5 seconds; a getcwd slower than that isn't worth using
     anyway.  */
  signal (SIGALRM, SIG_DFL);
  alarm (5);
# endif

  cwd = getcwd (buf, PATH_MAX);
  if (cwd == NULL)
    exit (10);

  cwd_len = initial_cwd_len = strlen (cwd);
  fail = 0;
  n_chdirs = 0;

  while (1)
    {
      size_t dotdot_max = PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN);
      char *c = NULL;

      cwd_len += DIR_NAME_SIZE;
      /* 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.  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)))
            #ifdef __linux__
            if (! (errno == EINVAL))
            #endif
              fail = 20;
          break;
        }

      if (PATH_MAX <= cwd_len && cwd_len < PATH_MAX + DIR_NAME_SIZE)
        {
          struct stat sb;

          c = getcwd (buf, PATH_MAX);
          if (!c && errno == ENOENT)
            {
              fail = 11;
              break;
            }
          if (c)
            {
              fail = 31;
              break;
            }
          if (! (errno == ERANGE || is_ENAMETOOLONG (errno)))
            {
              fail = 21;
              break;
            }

          /* Our replacement needs to be able to stat() long ../../paths,
             so generate a path larger than PATH_MAX to check,
             avoiding the replacement if we can't stat().  */
          c = getcwd (buf, cwd_len + 1);
          if (c && !AT_FDCWD && stat (c, &sb) != 0 && is_ENAMETOOLONG (errno))
            {
              fail = 32;
              break;
            }
        }

      if (dotdot_max <= cwd_len - initial_cwd_len)
        {
          if (dotdot_max + DIR_NAME_SIZE < cwd_len - initial_cwd_len)
            break;
          c = getcwd (buf, cwd_len + 1);
          if (!c)
            {
              if (! (errno == ERANGE || errno == ENOENT
                     || is_ENAMETOOLONG (errno)))
                {
                  fail = 22;
                  break;
                }
              if (AT_FDCWD || errno == ERANGE || errno == ENOENT)
                {
                  fail = 12;
                  break;
                }
            }
        }

      if (c && strlen (c) != cwd_len)
        {
          fail = 23;
          break;
        }
      ++n_chdirs;
    }

  /* Leaving behind such a deep directory is not polite.
     So clean up here, right away, even though the driving
     shell script would also clean up.  */
  {
    size_t i;

    /* Try rmdir first, in case the chdir failed.  */
    rmdir (DIR_NAME);
    for (i = 0; i <= n_chdirs; i++)
      {
        if (chdir ("..") < 0)
          break;
        if (rmdir (DIR_NAME) != 0)
          break;
      }
  }

  exit (fail);
#endif
}

Reply via email to