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