1*a7c91847Schristos#serial 10
2*a7c91847Schristos# Check for several getcwd bugs with long file names.
3*a7c91847Schristos# If so, arrange to compile the wrapper function.
4*a7c91847Schristos
5*a7c91847Schristos# This is necessary for at least GNU libc on linux-2.4.19 and 2.4.20.
6*a7c91847Schristos# I've heard that this is due to a Linux kernel bug, and that it has
7*a7c91847Schristos# been fixed between 2.4.21-pre3 and 2.4.21-pre4.  */
8*a7c91847Schristos
9*a7c91847Schristos# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
10*a7c91847Schristos# This file is free software; the Free Software Foundation
11*a7c91847Schristos# gives unlimited permission to copy and/or distribute it,
12*a7c91847Schristos# with or without modifications, as long as this notice is preserved.
13*a7c91847Schristos
14*a7c91847Schristos# From Jim Meyering
15*a7c91847Schristos
16*a7c91847SchristosAC_DEFUN([gl_FUNC_GETCWD_PATH_MAX],
17*a7c91847Schristos[
18*a7c91847Schristos  AC_CHECK_DECLS_ONCE(getcwd)
19*a7c91847Schristos  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
20*a7c91847Schristos  AC_CACHE_CHECK([whether getcwd handles long file names properly],
21*a7c91847Schristos    gl_cv_func_getcwd_path_max,
22*a7c91847Schristos    [# Arrange for deletion of the temporary directory this test creates.
23*a7c91847Schristos     ac_clean_files="$ac_clean_files confdir3"
24*a7c91847Schristos     AC_RUN_IFELSE(
25*a7c91847Schristos       [AC_LANG_SOURCE(
26*a7c91847Schristos	  [[
27*a7c91847Schristos#include <errno.h>
28*a7c91847Schristos#include <stdlib.h>
29*a7c91847Schristos#include <unistd.h>
30*a7c91847Schristos#include <string.h>
31*a7c91847Schristos#include <limits.h>
32*a7c91847Schristos#include <sys/stat.h>
33*a7c91847Schristos#include <sys/types.h>
34*a7c91847Schristos#include <fcntl.h>
35*a7c91847Schristos
36*a7c91847Schristos#ifndef AT_FDCWD
37*a7c91847Schristos# define AT_FDCWD 0
38*a7c91847Schristos#endif
39*a7c91847Schristos#ifdef ENAMETOOLONG
40*a7c91847Schristos# define is_ENAMETOOLONG(x) ((x) == ENAMETOOLONG)
41*a7c91847Schristos#else
42*a7c91847Schristos# define is_ENAMETOOLONG(x) 0
43*a7c91847Schristos#endif
44*a7c91847Schristos
45*a7c91847Schristos/* Don't get link errors because mkdir is redefined to rpl_mkdir.  */
46*a7c91847Schristos#undef mkdir
47*a7c91847Schristos
48*a7c91847Schristos#ifndef S_IRWXU
49*a7c91847Schristos# define S_IRWXU 0700
50*a7c91847Schristos#endif
51*a7c91847Schristos
52*a7c91847Schristos/* The length of this name must be 8.  */
53*a7c91847Schristos#define DIR_NAME "confdir3"
54*a7c91847Schristos#define DIR_NAME_LEN 8
55*a7c91847Schristos#define DIR_NAME_SIZE (DIR_NAME_LEN + 1)
56*a7c91847Schristos
57*a7c91847Schristos/* The length of "../".  */
58*a7c91847Schristos#define DOTDOTSLASH_LEN 3
59*a7c91847Schristos
60*a7c91847Schristos/* Leftover bytes in the buffer, to work around library or OS bugs.  */
61*a7c91847Schristos#define BUF_SLOP 20
62*a7c91847Schristos
63*a7c91847Schristosint
64*a7c91847Schristosmain (void)
65*a7c91847Schristos{
66*a7c91847Schristos#ifndef PATH_MAX
67*a7c91847Schristos  /* The Hurd doesn't define this, so getcwd can't exhibit the bug --
68*a7c91847Schristos     at least not on a local file system.  And if we were to start worrying
69*a7c91847Schristos     about remote file systems, we'd have to enable the wrapper function
70*a7c91847Schristos     all of the time, just to be safe.  That's not worth the cost.  */
71*a7c91847Schristos  exit (0);
72*a7c91847Schristos#elif ((INT_MAX / (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1) \
73*a7c91847Schristos        - DIR_NAME_SIZE - BUF_SLOP) \
74*a7c91847Schristos       <= PATH_MAX)
75*a7c91847Schristos  /* FIXME: Assuming there's a system for which this is true,
76*a7c91847Schristos     this should be done in a compile test.  */
77*a7c91847Schristos  exit (0);
78*a7c91847Schristos#else
79*a7c91847Schristos  char buf[PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN + 1)
80*a7c91847Schristos	   + DIR_NAME_SIZE + BUF_SLOP];
81*a7c91847Schristos  char *cwd = getcwd (buf, PATH_MAX);
82*a7c91847Schristos  size_t initial_cwd_len;
83*a7c91847Schristos  size_t cwd_len;
84*a7c91847Schristos  int fail = 0;
85*a7c91847Schristos  size_t n_chdirs = 0;
86*a7c91847Schristos
87*a7c91847Schristos  if (cwd == NULL)
88*a7c91847Schristos    exit (1);
89*a7c91847Schristos
90*a7c91847Schristos  cwd_len = initial_cwd_len = strlen (cwd);
91*a7c91847Schristos
92*a7c91847Schristos  while (1)
93*a7c91847Schristos    {
94*a7c91847Schristos      size_t dotdot_max = PATH_MAX * (DIR_NAME_SIZE / DOTDOTSLASH_LEN);
95*a7c91847Schristos      char *c = NULL;
96*a7c91847Schristos
97*a7c91847Schristos      cwd_len += DIR_NAME_SIZE;
98*a7c91847Schristos      /* If mkdir or chdir fails, it could be that this system cannot create
99*a7c91847Schristos	 any file with an absolute name longer than PATH_MAX, such as cygwin.
100*a7c91847Schristos	 If so, leave fail as 0, because the current working directory can't
101*a7c91847Schristos	 be too long for getcwd if it can't even be created.  For other
102*a7c91847Schristos	 errors, be pessimistic and consider that as a failure, too.  */
103*a7c91847Schristos      if (mkdir (DIR_NAME, S_IRWXU) < 0 || chdir (DIR_NAME) < 0)
104*a7c91847Schristos	{
105*a7c91847Schristos	  if (! (errno == ERANGE || is_ENAMETOOLONG (errno)))
106*a7c91847Schristos	    fail = 2;
107*a7c91847Schristos	  break;
108*a7c91847Schristos	}
109*a7c91847Schristos
110*a7c91847Schristos      if (PATH_MAX <= cwd_len && cwd_len < PATH_MAX + DIR_NAME_SIZE)
111*a7c91847Schristos	{
112*a7c91847Schristos	  c = getcwd (buf, PATH_MAX);
113*a7c91847Schristos	  if (!c && errno == ENOENT)
114*a7c91847Schristos	    {
115*a7c91847Schristos	      fail = 1;
116*a7c91847Schristos	      break;
117*a7c91847Schristos	    }
118*a7c91847Schristos	  if (c || ! (errno == ERANGE || is_ENAMETOOLONG (errno)))
119*a7c91847Schristos	    {
120*a7c91847Schristos	      fail = 2;
121*a7c91847Schristos	      break;
122*a7c91847Schristos	    }
123*a7c91847Schristos	}
124*a7c91847Schristos
125*a7c91847Schristos      if (dotdot_max <= cwd_len - initial_cwd_len)
126*a7c91847Schristos	{
127*a7c91847Schristos	  if (dotdot_max + DIR_NAME_SIZE < cwd_len - initial_cwd_len)
128*a7c91847Schristos	    break;
129*a7c91847Schristos	  c = getcwd (buf, cwd_len + 1);
130*a7c91847Schristos	  if (!c)
131*a7c91847Schristos	    {
132*a7c91847Schristos	      if (! (errno == ERANGE || errno == ENOENT
133*a7c91847Schristos		     || is_ENAMETOOLONG (errno)))
134*a7c91847Schristos		{
135*a7c91847Schristos		  fail = 2;
136*a7c91847Schristos		  break;
137*a7c91847Schristos		}
138*a7c91847Schristos	      if (AT_FDCWD || errno == ERANGE || errno == ENOENT)
139*a7c91847Schristos		{
140*a7c91847Schristos		  fail = 1;
141*a7c91847Schristos		  break;
142*a7c91847Schristos		}
143*a7c91847Schristos	    }
144*a7c91847Schristos	}
145*a7c91847Schristos
146*a7c91847Schristos      if (c && strlen (c) != cwd_len)
147*a7c91847Schristos	{
148*a7c91847Schristos	  fail = 2;
149*a7c91847Schristos	  break;
150*a7c91847Schristos	}
151*a7c91847Schristos      ++n_chdirs;
152*a7c91847Schristos    }
153*a7c91847Schristos
154*a7c91847Schristos  /* Leaving behind such a deep directory is not polite.
155*a7c91847Schristos     So clean up here, right away, even though the driving
156*a7c91847Schristos     shell script would also clean up.  */
157*a7c91847Schristos  {
158*a7c91847Schristos    size_t i;
159*a7c91847Schristos
160*a7c91847Schristos    /* Unlink first, in case the chdir failed.  */
161*a7c91847Schristos    unlink (DIR_NAME);
162*a7c91847Schristos    for (i = 0; i <= n_chdirs; i++)
163*a7c91847Schristos      {
164*a7c91847Schristos	if (chdir ("..") < 0)
165*a7c91847Schristos	  break;
166*a7c91847Schristos	rmdir (DIR_NAME);
167*a7c91847Schristos      }
168*a7c91847Schristos  }
169*a7c91847Schristos
170*a7c91847Schristos  exit (fail);
171*a7c91847Schristos#endif
172*a7c91847Schristos}
173*a7c91847Schristos          ]])],
174*a7c91847Schristos    [gl_cv_func_getcwd_path_max=yes],
175*a7c91847Schristos    [case $? in
176*a7c91847Schristos     1) gl_cv_func_getcwd_path_max='no, but it is partly working';;
177*a7c91847Schristos     *) gl_cv_func_getcwd_path_max=no;;
178*a7c91847Schristos     esac],
179*a7c91847Schristos    [gl_cv_func_getcwd_path_max=no])
180*a7c91847Schristos  ])
181*a7c91847Schristos  case $gl_cv_func_getcwd_path_max in
182*a7c91847Schristos  no,*)
183*a7c91847Schristos    AC_DEFINE([HAVE_PARTLY_WORKING_GETCWD], 1,
184*a7c91847Schristos      [Define to 1 if getcwd works, except it sometimes fails when it shouldn't,
185*a7c91847Schristos       setting errno to ERANGE, ENAMETOOLONG, or ENOENT.  If __GETCWD_PREFIX
186*a7c91847Schristos       is not defined, it doesn't matter whether HAVE_PARTLY_WORKING_GETCWD
187*a7c91847Schristos       is defined.]);;
188*a7c91847Schristos  esac
189*a7c91847Schristos])
190