changeset 14629:7a493fbc787a

getcwd-lgpl: new module For programs that aren't worried about being invoked from an current working directory longer than PATH_MAX (perhaps because the program always does chdir to a sane location first), the getcwd module is overkill, given that all modern portability targets have a getcwd that works on short names. * modules/getcwd-lgpl: New module. * lib/getcwd-lgpl.c: New file. * doc/posix-functions/getcwd.texi (getcwd): Document it. * MODULES.html.sh (lacking POSIX:2008): Likewise. * modules/getcwd (configure.ac): Set C witness. * m4/getcwd.m4 (gl_FUNC_GETCWD_LGPL): New macro. Signed-off-by: Eric Blake <eblake@redhat.com>
author Eric Blake <eblake@redhat.com>
date Tue, 26 Apr 2011 14:40:58 -0600
parents a54d85d62606
children d9dece4023b0
files ChangeLog MODULES.html.sh doc/posix-functions/getcwd.texi lib/getcwd-lgpl.c m4/getcwd.m4 modules/getcwd modules/getcwd-lgpl
diffstat 7 files changed, 190 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Apr 26 11:27:15 2011 -0600
+++ b/ChangeLog	Tue Apr 26 14:40:58 2011 -0600
@@ -1,5 +1,13 @@
 2011-04-27  Eric Blake  <eblake@redhat.com>
 
+	getcwd-lgpl: new module
+	* modules/getcwd-lgpl: New module.
+	* lib/getcwd-lgpl.c: New file.
+	* doc/posix-functions/getcwd.texi (getcwd): Document it.
+	* MODULES.html.sh (lacking POSIX:2008): Likewise.
+	* modules/getcwd (configure.ac): Set C witness.
+	* m4/getcwd.m4 (gl_FUNC_GETCWD_LGPL): New macro.
+
 	getcwd: tweak comments
 	* m4/getcwd-abort-bug.m4: Fix comments.
 	* m4/getcwd-path-max.m4: Likewise.
--- a/MODULES.html.sh	Tue Apr 26 11:27:15 2011 -0600
+++ b/MODULES.html.sh	Tue Apr 26 14:40:58 2011 -0600
@@ -2353,6 +2353,7 @@
   func_module futimens
   func_module getaddrinfo
   func_module getcwd
+  func_module getcwd-lgpl
   func_module getgroups
   func_module gethostname
   func_module getlogin
--- a/doc/posix-functions/getcwd.texi	Tue Apr 26 11:27:15 2011 -0600
+++ b/doc/posix-functions/getcwd.texi	Tue Apr 26 14:40:58 2011 -0600
@@ -4,16 +4,21 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/getcwd.html}
 
-Gnulib module: getcwd
+Gnulib module: getcwd or getcwd-lgpl
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by either Gnulib module @code{getcwd} or
+@code{getcwd-lgpl}:
+@itemize
+@item
+On glibc platforms, @code{getcwd (NULL, n)} allocates memory for the result.
+On other platforms, this call is not allowed.
+@end itemize
+
+Portability problems fixed by Gnulib module @code{getcwd}:
 @itemize
 @item
 This function is missing on some older platforms.
 @item
-On glibc platforms, @code{getcwd (NULL, n)} allocates memory for the result.
-On other platforms, this call is not allowed.
-@item
 This function does not handle long file names (greater than @code{PATH_MAX})
 correctly on some platforms.
 @end itemize
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/getcwd-lgpl.c	Tue Apr 26 14:40:58 2011 -0600
@@ -0,0 +1,118 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+   This file is part of gnulib.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification */
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+
+#if GNULIB_GETCWD
+/* Favor GPL getcwd.c if both getcwd and getcwd-lgpl modules are in use.  */
+typedef int dummy;
+#else
+
+/* Get the name of the current working directory, and put it in SIZE
+   bytes of BUF.  Returns NULL if the directory couldn't be determined
+   (perhaps because the absolute name was longer than PATH_MAX, or
+   because of missing read/search permissions on parent directories)
+   or SIZE was too small.  If successful, returns BUF.  If BUF is
+   NULL, an array is allocated with `malloc'; the array is SIZE bytes
+   long, unless SIZE == 0, in which case it is as big as
+   necessary.  */
+
+# undef getcwd
+char *
+rpl_getcwd (char *buf, size_t size)
+{
+  char *ptr;
+  char *result;
+
+  /* Handle single size operations.  */
+  if (buf)
+    return getcwd (buf, size);
+
+  if (size)
+    {
+      buf = malloc (size);
+      if (!buf)
+        {
+          errno = ENOMEM;
+          return -1;
+        }
+      result = getcwd (buf, size);
+      if (!result)
+        {
+          int saved_errno = errno;
+          free (buf);
+          errno = saved_errno;
+        }
+      return result;
+    }
+
+  /* Flexible sizing requested.  Avoid over-allocation for the common
+     case of a name that fits within a 4k page, minus some space for
+     local variables, to be sure we don't skip over a guard page.  */
+  {
+    char tmp[4032];
+    size = sizeof tmp;
+    ptr = getcwd (tmp, size);
+    if (ptr)
+      {
+        result = strdup (ptr);
+        if (!result)
+          errno = ENOMEM;
+        return result;
+      }
+    if (errno != ERANGE)
+      return NULL;
+  }
+
+  /* My what a large directory name we have.  */
+  do
+    {
+      size <<= 1;
+      ptr = realloc (buf, size);
+      if (ptr == NULL)
+        {
+          free (buf);
+          errno = ENOMEM;
+          return NULL;
+        }
+      buf = ptr;
+      result = getcwd (buf, size);
+    }
+  while (!result && errno == ERANGE);
+
+  if (!result)
+    {
+      int saved_errno = errno;
+      free (buf);
+      errno = saved_errno;
+    }
+  else
+    {
+      /* Trim to fit, if possible.  */
+      result = realloc (buf, strlen (buf) + 1);
+      if (!result)
+        result = buf;
+    }
+  return result;
+}
+
+#endif
--- a/m4/getcwd.m4	Tue Apr 26 11:27:15 2011 -0600
+++ b/m4/getcwd.m4	Tue Apr 26 14:40:58 2011 -0600
@@ -6,10 +6,11 @@
 # with or without modifications, as long as this notice is preserved.
 
 # Written by Paul Eggert.
-# serial 4
+# serial 5
 
 AC_DEFUN([gl_FUNC_GETCWD_NULL],
   [
+   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
    AC_CACHE_CHECK([whether getcwd (NULL, 0) allocates memory for result],
      [gl_cv_func_getcwd_null],
      [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
@@ -52,6 +53,29 @@
         ]])])
 ])
 
+
+dnl Guarantee that getcwd will malloc with a NULL first argument.  Assumes
+dnl that either the system getcwd is robust, or that calling code is okay
+dnl with spurious failures when run from a directory with an absolute name
+dnl larger than 4k bytes.
+dnl
+dnl Assumes that getcwd exists; if you are worried about obsolete
+dnl platforms that lacked getcwd(), then you need to use the GPL module.
+AC_DEFUN([gl_FUNC_GETCWD_LGPL],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_REQUIRE([gl_FUNC_GETCWD_NULL])
+
+  case $gl_cv_func_getcwd_null in
+  *yes) ;;
+  *)
+    dnl Minimal replacement
+    REPLACE_GETCWD=1
+    AC_LIBOBJ([getcwd-lgpl])
+    ;;
+  esac
+])
+
 dnl Check for all known getcwd bugs; useful for a program likely to be
 dnl executed from an arbitrary location.
 AC_DEFUN([gl_FUNC_GETCWD],
@@ -72,13 +96,14 @@
   case $gl_cv_func_getcwd_null,$gl_cv_func_getcwd_path_max,$gl_abort_bug in
   *yes,yes,no) ;;
   *)
+    dnl Full replacement, overrides LGPL replacement.
     REPLACE_GETCWD=1
     AC_LIBOBJ([getcwd])
     gl_PREREQ_GETCWD;;
   esac
 ])
 
-# Prerequisites of lib/getcwd.c.
+# Prerequisites of lib/getcwd.c, when full replacement is in effect.
 AC_DEFUN([gl_PREREQ_GETCWD],
 [
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
--- a/modules/getcwd	Tue Apr 26 11:27:15 2011 -0600
+++ b/modules/getcwd	Tue Apr 26 14:40:58 2011 -0600
@@ -20,6 +20,7 @@
 
 configure.ac:
 gl_FUNC_GETCWD
+gl_MODULE_INDICATOR([getcwd])
 gl_UNISTD_MODULE_INDICATOR([getcwd])
 
 Makefile.am:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/getcwd-lgpl	Tue Apr 26 14:40:58 2011 -0600
@@ -0,0 +1,25 @@
+Description:
+Ensure getcwd(NULL, 0) returns a buffer allocated by malloc().
+
+Files:
+lib/getcwd-lgpl.c
+m4/getcwd.m4
+
+Depends-on:
+strdup
+unistd
+
+configure.ac:
+gl_FUNC_GETCWD_LGPL
+gl_UNISTD_MODULE_INDICATOR([getcwd])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+Eric Blake