changeset 16113:80ff47677300

getcwd: Work around getcwd bug on AIX 5..7. * m4/getcwd-path-max.m4 (gl_FUNC_GETCWD_PATH_MAX): Require AC_CANONICAL_HOST. Assign exit code 31 to the bug seen on AIX 5.1..7.1. Use a different value for gl_cv_func_getcwd_path_max. Move the definition of HAVE_PARTLY_WORKING_GETCWD from here... * m4/getcwd.m4 (gl_FUNC_GETCWD): ... to here. Invoke gl_FUNC_GETCWD_PATH_MAX also when $gl_cv_func_getcwd_null is 'no'. Define HAVE_MINIMALLY_WORKING_GETCWD. * lib/getcwd.c (__getcwd): Don't use the system's getcwd on platforms where it is not even minimally working, that is, on AIX. * tests/test-getcwd.c (test_long_name): Distinguish the same cases as m4/getcwd-path-max.m4. (main): Update exit code computation. * doc/posix-functions/getcwd.texi: Mention list of platforms where getcwd does not handle long file names.
author Bruno Haible <bruno@clisp.org>
date Mon, 21 Nov 2011 00:56:11 +0100
parents c676f6041c6c
children cb89957e23c8
files ChangeLog doc/posix-functions/getcwd.texi lib/getcwd.c m4/getcwd-path-max.m4 m4/getcwd.m4 tests/test-getcwd.c
diffstat 6 files changed, 68 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2011-11-20  Bruno Haible  <bruno@clisp.org>
+
+	getcwd: Work around getcwd bug on AIX 5..7.
+	* m4/getcwd-path-max.m4 (gl_FUNC_GETCWD_PATH_MAX): Require
+	AC_CANONICAL_HOST. Assign exit code 31 to the bug seen on AIX 5.1..7.1.
+	Use a different value for gl_cv_func_getcwd_path_max. Move the
+	definition of HAVE_PARTLY_WORKING_GETCWD from here...
+	* m4/getcwd.m4 (gl_FUNC_GETCWD): ... to here. Invoke
+	gl_FUNC_GETCWD_PATH_MAX also when $gl_cv_func_getcwd_null is 'no'.
+	Define HAVE_MINIMALLY_WORKING_GETCWD.
+	* lib/getcwd.c (__getcwd): Don't use the system's getcwd on platforms
+	where it is not even minimally working, that is, on AIX.
+	* tests/test-getcwd.c (test_long_name): Distinguish the same cases as
+	m4/getcwd-path-max.m4.
+	(main): Update exit code computation.
+	* doc/posix-functions/getcwd.texi: Mention list of platforms where
+	getcwd does not handle long file names.
+
 2011-11-20  Bruno Haible  <bruno@clisp.org>
 
 	getcwd: Fix bug from 2009-09-10.
--- a/doc/posix-functions/getcwd.texi
+++ b/doc/posix-functions/getcwd.texi
@@ -33,7 +33,8 @@
 This function is missing on some older platforms.
 @item
 This function does not handle long file names (greater than @code{PATH_MAX})
-correctly on some platforms.
+correctly on some platforms:
+glibc on Linux 2.4.20, MacOS X 10.5, FreeBSD 6.4, NetBSD 5.1, OpenBSD 4.9, AIX 7.1.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/lib/getcwd.c
+++ b/lib/getcwd.c
@@ -135,7 +135,7 @@
   size_t allocated = size;
   size_t used;
 
-#if HAVE_RAW_DECL_GETCWD
+#if HAVE_RAW_DECL_GETCWD && HAVE_MINIMALLY_WORKING_GETCWD
   /* If AT_FDCWD is not defined, the algorithm below is O(N**2) and
      this is much slower than the system getcwd (at least on
      GNU/Linux).  So trust the system getcwd's results unless they
@@ -143,7 +143,12 @@
 
      Use the system getcwd even if we have openat support, since the
      system getcwd works even when a parent is unreadable, while the
-     openat-based approach does not.  */
+     openat-based approach does not.
+
+     But on AIX 5.1..7.1, the system getcwd is not even minimally
+     working: If the current directory name is slightly longer than
+     PATH_MAX, it omits the first directory component and returns
+     this wrong result with errno = 0.  */
 
 # undef getcwd
   dir = getcwd (buf, size);
--- a/m4/getcwd-path-max.m4
+++ b/m4/getcwd-path-max.m4
@@ -1,4 +1,4 @@
-# serial 18
+# serial 19
 # Check for several getcwd bugs with long file names.
 # If so, arrange to compile the wrapper function.
 
@@ -16,6 +16,7 @@
 AC_DEFUN([gl_FUNC_GETCWD_PATH_MAX],
 [
   AC_CHECK_DECLS_ONCE([getcwd])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   AC_CHECK_HEADERS_ONCE([unistd.h])
   AC_REQUIRE([gl_PATHMAX_SNIPPET_PREREQ])
@@ -124,7 +125,12 @@
               fail = 11;
               break;
             }
-          if (c || ! (errno == ERANGE || is_ENAMETOOLONG (errno)))
+          if (c)
+            {
+              fail = 31;
+              break;
+            }
+          if (! (errno == ERANGE || is_ENAMETOOLONG (errno)))
             {
               fail = 21;
               break;
@@ -184,14 +190,12 @@
     [gl_cv_func_getcwd_path_max=yes],
     [case $? in
      10|11|12) gl_cv_func_getcwd_path_max='no, but it is partly working';;
+     31) gl_cv_func_getcwd_path_max='no, it has the AIX bug';;
      *) gl_cv_func_getcwd_path_max=no;;
      esac],
-    [gl_cv_func_getcwd_path_max=no])
+    [case "$host_os" in
+       aix*) gl_cv_func_getcwd_path_max='no, it has the AIX bug';;
+       *) gl_cv_func_getcwd_path_max=no;;
+     esac])
   ])
-  case $gl_cv_func_getcwd_path_max in
-  no,*)
-    AC_DEFINE([HAVE_PARTLY_WORKING_GETCWD], [1],
-      [Define to 1 if getcwd works, except it sometimes fails when it shouldn't,
-       setting errno to ERANGE, ENAMETOOLONG, or ENOENT.]);;
-  esac
 ])
--- a/m4/getcwd.m4
+++ b/m4/getcwd.m4
@@ -113,14 +113,31 @@
       gl_cv_func_getcwd_path_max=yes
       ;;
     *)
+      gl_FUNC_GETCWD_PATH_MAX
       case "$gl_cv_func_getcwd_null" in
         *yes)
-          gl_FUNC_GETCWD_PATH_MAX
           gl_FUNC_GETCWD_ABORT_BUG([gl_abort_bug=yes])
           ;;
       esac
       ;;
   esac
+  dnl Define HAVE_MINIMALLY_WORKING_GETCWD and HAVE_PARTLY_WORKING_GETCWD
+  dnl if appropriate.
+  case "$gl_cv_func_getcwd_path_max" in
+    "no, it has the AIX bug") ;;
+    *)
+      AC_DEFINE([HAVE_MINIMALLY_WORKING_GETCWD], [1],
+        [Define to 1 if getcwd minimally works, that is, its result can be
+         trusted when it succeeds.])
+      ;;
+  esac
+  case "$gl_cv_func_getcwd_path_max" in
+    "no, but it is partly working")
+      AC_DEFINE([HAVE_PARTLY_WORKING_GETCWD], [1],
+        [Define to 1 if getcwd works, except it sometimes fails when it
+         shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT.])
+      ;;
+  esac
 
   case $gl_cv_func_getcwd_null,$gl_cv_func_getcwd_posix_signature$gl_cv_func_getcwd_path_max,$gl_abort_bug in
   *yes,yes,yes,no) ;;
--- a/tests/test-getcwd.c
+++ b/tests/test-getcwd.c
@@ -164,11 +164,16 @@
               fail = 3;
               break;
             }
-          if (c || ! (errno == ERANGE || errno == ENAMETOOLONG))
+          if (c)
             {
               fail = 4;
               break;
             }
+          if (! (errno == ERANGE || errno == ENAMETOOLONG))
+            {
+              fail = 5;
+              break;
+            }
         }
 
       if (dotdot_max <= cwd_len - initial_cwd_len)
@@ -181,12 +186,12 @@
               if (! (errno == ERANGE || errno == ENOENT
                      || errno == ENAMETOOLONG))
                 {
-                  fail = 5;
+                  fail = 6;
                   break;
                 }
               if (AT_FDCWD || errno == ERANGE || errno == ENOENT)
                 {
-                  fail = 6;
+                  fail = 7;
                   break;
                 }
             }
@@ -194,7 +199,7 @@
 
       if (c && strlen (c) != cwd_len)
         {
-          fail = 7;
+          fail = 8;
           break;
         }
       ++n_chdirs;
@@ -224,5 +229,5 @@
 int
 main (int argc, char **argv)
 {
-  return test_abort_bug () * 8 + test_long_name ();
+  return test_abort_bug () * 10 + test_long_name ();
 }