| 1 | # serial 11 |
| 2 | # Determine whether getcwd aborts when the length of the working directory |
| 3 | # name is unusually large. Any length between 4k and 16k trigger the bug |
| 4 | # when using glibc-2.4.90-9 or older. |
| 5 | |
| 6 | # Copyright (C) 2006, 2009-2020 Free Software Foundation, Inc. |
| 7 | # This file is free software; the Free Software Foundation |
| 8 | # gives unlimited permission to copy and/or distribute it, |
| 9 | # with or without modifications, as long as this notice is preserved. |
| 10 | |
| 11 | # From Jim Meyering |
| 12 | |
| 13 | # gl_FUNC_GETCWD_ABORT_BUG([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) |
| 14 | AC_DEFUN([gl_FUNC_GETCWD_ABORT_BUG], |
| 15 | [ |
| 16 | AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles |
| 17 | AC_CHECK_DECLS_ONCE([getcwd]) |
| 18 | AC_CHECK_HEADERS_ONCE([unistd.h]) |
| 19 | AC_REQUIRE([gl_PATHMAX_SNIPPET_PREREQ]) |
| 20 | |
| 21 | gl_CHECK_FUNC_GETPAGESIZE |
| 22 | if test $gl_cv_func_getpagesize = yes; then |
| 23 | AC_DEFINE_UNQUOTED([HAVE_GETPAGESIZE], [1], |
| 24 | [Define to 1 if the system has the 'getpagesize' function.]) |
| 25 | fi |
| 26 | |
| 27 | AC_CACHE_CHECK([whether getcwd aborts when 4k < cwd_length < 16k], |
| 28 | [gl_cv_func_getcwd_abort_bug], |
| 29 | [# Remove any remnants of a previous test. |
| 30 | rm -rf confdir-14B--- |
| 31 | # Arrange for deletion of the temporary directory this test creates. |
| 32 | ac_clean_files="$ac_clean_files confdir-14B---" |
| 33 | dnl Please keep this in sync with tests/test-getcwd.c. |
| 34 | AC_RUN_IFELSE( |
| 35 | [AC_LANG_SOURCE( |
| 36 | [[ |
| 37 | #include <errno.h> |
| 38 | #include <stdlib.h> |
| 39 | #if HAVE_UNISTD_H |
| 40 | # include <unistd.h> |
| 41 | #else /* on Windows with MSVC */ |
| 42 | # include <direct.h> |
| 43 | #endif |
| 44 | #include <string.h> |
| 45 | #include <sys/stat.h> |
| 46 | |
| 47 | ]gl_PATHMAX_SNIPPET[ |
| 48 | |
| 49 | /* Don't get link errors because mkdir is redefined to rpl_mkdir. */ |
| 50 | #undef mkdir |
| 51 | |
| 52 | #ifndef S_IRWXU |
| 53 | # define S_IRWXU 0700 |
| 54 | #endif |
| 55 | |
| 56 | /* FIXME: skip the run-test altogether on systems without getpagesize. */ |
| 57 | #if ! HAVE_GETPAGESIZE |
| 58 | # define getpagesize() 0 |
| 59 | #endif |
| 60 | |
| 61 | /* This size is chosen to be larger than PATH_MAX (4k), yet smaller than |
| 62 | the 16kB pagesize on ia64 linux. Those conditions make the code below |
| 63 | trigger a bug in glibc's getcwd implementation before 2.4.90-10. */ |
| 64 | #define TARGET_LEN (5 * 1024) |
| 65 | |
| 66 | int |
| 67 | main () |
| 68 | { |
| 69 | char *cwd; |
| 70 | size_t initial_cwd_len; |
| 71 | int fail = 0; |
| 72 | |
| 73 | /* The bug is triggered when PATH_MAX < getpagesize (), so skip |
| 74 | this relatively expensive and invasive test if that's not true. */ |
| 75 | #ifdef PATH_MAX |
| 76 | int bug_possible = PATH_MAX < getpagesize (); |
| 77 | #else |
| 78 | int bug_possible = 0; |
| 79 | #endif |
| 80 | if (! bug_possible) |
| 81 | return 0; |
| 82 | |
| 83 | cwd = getcwd (NULL, 0); |
| 84 | if (cwd == NULL) |
| 85 | return 2; |
| 86 | |
| 87 | initial_cwd_len = strlen (cwd); |
| 88 | free (cwd); |
| 89 | |
| 90 | if (1) |
| 91 | { |
| 92 | static char const dir_name[] = "confdir-14B---"; |
| 93 | size_t desired_depth = ((TARGET_LEN - 1 - initial_cwd_len) |
| 94 | / sizeof dir_name); |
| 95 | size_t d; |
| 96 | for (d = 0; d < desired_depth; d++) |
| 97 | { |
| 98 | if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0) |
| 99 | { |
| 100 | if (! (errno == ERANGE || errno == ENAMETOOLONG |
| 101 | || errno == ENOENT)) |
| 102 | fail = 3; /* Unable to construct deep hierarchy. */ |
| 103 | break; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | /* If libc has the bug in question, this invocation of getcwd |
| 108 | results in a failed assertion. */ |
| 109 | cwd = getcwd (NULL, 0); |
| 110 | if (cwd == NULL) |
| 111 | fail = 4; /* getcwd didn't assert, but it failed for a long name |
| 112 | where the answer could have been learned. */ |
| 113 | free (cwd); |
| 114 | |
| 115 | /* Call rmdir first, in case the above chdir failed. */ |
| 116 | rmdir (dir_name); |
| 117 | while (0 < d--) |
| 118 | { |
| 119 | if (chdir ("..") < 0) |
| 120 | { |
| 121 | fail = 5; |
| 122 | break; |
| 123 | } |
| 124 | rmdir (dir_name); |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | return fail; |
| 129 | } |
| 130 | ]])], |
| 131 | [gl_cv_func_getcwd_abort_bug=no], |
| 132 | [dnl An abort will provoke an exit code of something like 134 (128 + 6). |
| 133 | dnl An exit code of 4 can also occur (in OpenBSD 4.9, NetBSD 5.1 for |
| 134 | dnl example): getcwd (NULL, 0) fails rather than returning a string |
| 135 | dnl longer than PATH_MAX. This may be POSIX compliant (in some |
| 136 | dnl interpretations of POSIX). But gnulib's getcwd module wants to |
| 137 | dnl provide a non-NULL value in this case. |
| 138 | ret=$? |
| 139 | if test $ret -ge 128 || test $ret = 4; then |
| 140 | gl_cv_func_getcwd_abort_bug=yes |
| 141 | else |
| 142 | gl_cv_func_getcwd_abort_bug=no |
| 143 | fi |
| 144 | ], |
| 145 | [case "$host_os" in |
| 146 | # Guess no on musl systems. |
| 147 | *-musl*) gl_cv_func_getcwd_abort_bug="guessing no" ;; |
| 148 | # Guess yes otherwise, even on glibc systems. |
| 149 | *) gl_cv_func_getcwd_abort_bug="guessing yes" |
| 150 | esac |
| 151 | ]) |
| 152 | ]) |
| 153 | case "$gl_cv_func_getcwd_abort_bug" in |
| 154 | *yes) |
| 155 | $1 |
| 156 | ;; |
| 157 | *) |
| 158 | $2 |
| 159 | ;; |
| 160 | esac |
| 161 | ]) |