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