| # serial 15 |
| # Determine whether getcwd aborts when the length of the working directory |
| # name is unusually large. Any length between 4k and 16k trigger the bug |
| # when using glibc-2.4.90-9 or older. |
| |
| # Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc. |
| # This file is free software; the Free Software Foundation |
| # gives unlimited permission to copy and/or distribute it, |
| # with or without modifications, as long as this notice is preserved. |
| |
| # From Jim Meyering |
| |
| # gl_FUNC_GETCWD_ABORT_BUG([ACTION-IF-BUGGY[, ACTION-IF-WORKS]]) |
| AC_DEFUN([gl_FUNC_GETCWD_ABORT_BUG], |
| [ |
| AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles |
| AC_CHECK_DECLS_ONCE([getcwd]) |
| AC_CHECK_HEADERS_ONCE([unistd.h]) |
| AC_REQUIRE([gl_PATHMAX_SNIPPET_PREREQ]) |
| |
| gl_CHECK_FUNC_GETPAGESIZE |
| if test $gl_cv_func_getpagesize = yes; then |
| AC_DEFINE_UNQUOTED([HAVE_GETPAGESIZE], [1], |
| [Define to 1 if the system has the 'getpagesize' function.]) |
| fi |
| |
| AC_CACHE_CHECK([whether getcwd succeeds when 4k < cwd_length < 16k], |
| [gl_cv_func_getcwd_succeeds_beyond_4k], |
| [# Remove any remnants of a previous test. |
| rm -rf confdir-14B--- |
| # Arrange for deletion of the temporary directory this test creates. |
| ac_clean_files="$ac_clean_files confdir-14B---" |
| dnl Please keep this in sync with tests/test-getcwd.c. |
| AC_RUN_IFELSE( |
| [AC_LANG_SOURCE( |
| [[ |
| #include <errno.h> |
| #include <stdlib.h> |
| #if HAVE_UNISTD_H |
| # include <unistd.h> |
| #else /* on Windows with MSVC */ |
| # include <direct.h> |
| #endif |
| #include <string.h> |
| #include <sys/stat.h> |
| |
| ]gl_PATHMAX_SNIPPET[ |
| ]GL_MDA_DEFINES[ |
| |
| #ifndef S_IRWXU |
| # define S_IRWXU 0700 |
| #endif |
| |
| /* FIXME: skip the run-test altogether on systems without getpagesize. */ |
| #if ! HAVE_GETPAGESIZE |
| # define getpagesize() 0 |
| #endif |
| |
| /* This size is chosen to be larger than PATH_MAX (4k), yet smaller than |
| the 16kB pagesize on ia64 linux. Those conditions make the code below |
| trigger a bug in glibc's getcwd implementation before 2.4.90-10. */ |
| #define TARGET_LEN (5 * 1024) |
| |
| int |
| main () |
| { |
| char *cwd; |
| size_t initial_cwd_len; |
| int fail = 0; |
| |
| /* The bug is triggered when PATH_MAX < getpagesize (), so skip |
| this relatively expensive and invasive test if that's not true. */ |
| #ifdef PATH_MAX |
| int bug_possible = PATH_MAX < getpagesize (); |
| #else |
| int bug_possible = 0; |
| #endif |
| if (! bug_possible) |
| return 0; |
| |
| cwd = getcwd (NULL, 0); |
| if (cwd == NULL) |
| return 2; |
| |
| initial_cwd_len = strlen (cwd); |
| free (cwd); |
| |
| if (1) |
| { |
| static char const dir_name[] = "confdir-14B---"; |
| size_t desired_depth = ((TARGET_LEN - 1 - initial_cwd_len) |
| / sizeof dir_name); |
| size_t d; |
| for (d = 0; d < desired_depth; d++) |
| { |
| if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0) |
| { |
| if (! (errno == ERANGE || errno == ENAMETOOLONG |
| || errno == ENOENT)) |
| fail = 3; /* Unable to construct deep hierarchy. */ |
| break; |
| } |
| } |
| |
| /* If libc has the bug in question, this invocation of getcwd |
| results in a failed assertion. */ |
| cwd = getcwd (NULL, 0); |
| if (cwd == NULL) |
| fail = 4; /* getcwd didn't assert, but it failed for a long name |
| where the answer could have been learned. */ |
| free (cwd); |
| |
| /* Call rmdir first, in case the above chdir failed. */ |
| rmdir (dir_name); |
| while (0 < d--) |
| { |
| if (chdir ("..") < 0) |
| { |
| fail = 5; |
| break; |
| } |
| rmdir (dir_name); |
| } |
| } |
| |
| return fail; |
| } |
| ]])], |
| [gl_cv_func_getcwd_succeeds_beyond_4k=yes], |
| [dnl An abort will provoke an exit code of something like 134 (128 + 6). |
| dnl An exit code of 4 can also occur (in OpenBSD 6.7, NetBSD 5.1 for |
| dnl example): getcwd (NULL, 0) fails rather than returning a string |
| dnl longer than PATH_MAX. This may be POSIX compliant (in some |
| dnl interpretations of POSIX). But gnulib's getcwd module wants to |
| dnl provide a non-NULL value in this case. |
| ret=$? |
| if test $ret -ge 128 || test $ret = 4; then |
| gl_cv_func_getcwd_succeeds_beyond_4k=no |
| else |
| gl_cv_func_getcwd_succeeds_beyond_4k=yes |
| fi |
| ], |
| [case "$host_os" in |
| # Guess yes on musl systems. |
| *-musl*) gl_cv_func_getcwd_succeeds_beyond_4k="guessing yes" ;; |
| # Guess no otherwise, even on glibc systems. |
| *) gl_cv_func_getcwd_succeeds_beyond_4k="guessing no" |
| esac |
| ]) |
| ]) |
| case "$gl_cv_func_getcwd_succeeds_beyond_4k" in |
| *no) |
| $1 |
| ;; |
| *) |
| $2 |
| ;; |
| esac |
| ]) |