New getcwd module, imported from coreutils.
[gnulib.git] / m4 / getcwd-path-max.m4
1 #serial 4
2 # Check whether getcwd has the bug that it succeeds for a working directory
3 # longer than PATH_MAX, yet returns a truncated directory name.
4 # If so, arrange to compile the wrapper function.
5
6 # This is necessary for at least GNU libc on linux-2.4.19 and 2.4.20.
7 # I've heard that this is due to a Linux kernel bug, and that it has
8 # been fixed between 2.4.21-pre3 and 2.4.21-pre4.  */
9
10 # Copyright (C) 2003, 2004 Free Software Foundation, Inc.
11
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2, or (at your option)
15 # any later version.
16
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU General Public License for more details.
21
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software Foundation,
24 # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 # From Jim Meyering
27
28 AC_DEFUN([GL_FUNC_GETCWD_PATH_MAX],
29 [
30   AC_CHECK_DECLS([getcwd])
31   AC_CACHE_CHECK([whether getcwd properly handles paths longer than PATH_MAX],
32                  gl_cv_func_getcwd_vs_path_max,
33   [
34   # Arrange for deletion of the temporary directory this test creates.
35   ac_clean_files="$ac_clean_files confdir3"
36   AC_RUN_IFELSE([AC_LANG_SOURCE([[
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <limits.h>
41 #include <sys/stat.h>
42 #include <sys/types.h>
43
44 /* Don't get link errors because mkdir is redefined to rpl_mkdir.  */
45 #undef mkdir
46
47 #ifndef CHAR_BIT
48 # define CHAR_BIT 8
49 #endif
50
51 /* The extra casts work around common compiler bugs.  */
52 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
53 /* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
54    It is necessary at least when t == time_t.  */
55 #define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
56                               ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
57 #define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
58
59 #ifndef INT_MAX
60 # define INT_MAX TYPE_MAXIMUM (int)
61 #endif
62
63 /* The length of this name must be 8.  */
64 #define DIR_NAME "confdir3"
65
66 int
67 main ()
68 {
69 #ifndef PATH_MAX
70   /* The Hurd doesn't define this, so getcwd can't exhibit the bug --
71      at least not on a local file system.  And if we were to start worrying
72      about remote file systems, we'd have to enable the wrapper function
73      all of the time, just to be safe.  That's not worth the cost.  */
74   exit (0);
75 #elif INT_MAX - 9 <= PATH_MAX
76   /* The '9', above, comes from strlen (DIR_NAME) + 1.  */
77   /* FIXME: Assuming there's a system for which this is true,
78      this should be done in a compile test.  */
79   exit (0);
80 #else
81   char buf[PATH_MAX + 20];
82   char *cwd = getcwd (buf, PATH_MAX);
83   size_t cwd_len;
84   int fail = 0;
85   size_t n_chdirs = 0;
86
87   if (cwd == NULL)
88     exit (1);
89
90   cwd_len = strlen (cwd);
91
92   while (1)
93     {
94       char *c;
95       size_t len;
96
97       cwd_len += 1 + strlen (DIR_NAME);
98       /* If mkdir or chdir fails, be pessimistic and consider that
99          as a failure, too.  */
100       if (mkdir (DIR_NAME, 0700) < 0 || chdir (DIR_NAME) < 0)
101         {
102           fail = 1;
103           break;
104         }
105       if ((c = getcwd (buf, PATH_MAX)) == NULL)
106         {
107           /* This allows any failure to indicate there is no bug.
108              FIXME: check errno?  */
109           break;
110         }
111       if ((len = strlen (c)) != cwd_len)
112         {
113           fail = 1;
114           break;
115         }
116       ++n_chdirs;
117       if (PATH_MAX < len)
118         break;
119     }
120
121   /* Leaving behind such a deep directory is not polite.
122      So clean up here, right away, even though the driving
123      shell script would also clean up.  */
124   {
125     size_t i;
126
127     /* Unlink first, in case the chdir failed.  */
128     unlink (DIR_NAME);
129     for (i = 0; i <= n_chdirs; i++)
130       {
131         if (chdir ("..") < 0)
132           break;
133         rmdir (DIR_NAME);
134       }
135   }
136
137   exit (fail);
138 #endif
139 }
140   ]])],
141        [gl_cv_func_getcwd_vs_path_max=yes],
142        [gl_cv_func_getcwd_vs_path_max=no],
143        [gl_cv_func_getcwd_vs_path_max=no])])
144
145   if test $gl_cv_func_getcwd_vs_path_max = no; then
146     AC_LIBOBJ(getcwd)
147     AC_DEFINE(getcwd, rpl_getcwd,
148       [Define to rpl_getcwd if the wrapper function should be used.])
149   fi
150 ])