diff --git a/src/acconfig.h b/src/acconfig.h index 2bd41b04e63a0bca172c176f173f4a902422eb3b..9e3cb9e8d4f03c0a7103445544cef9321a0c9a4f 100644 --- a/src/acconfig.h +++ b/src/acconfig.h @@ -153,7 +153,14 @@ * __chkstk. */ #undef HAVE_BROKEN_CHKSTK -/* Define if you have a working getcwd */ +/* Define if you have a working getcwd(3) (ie one that returns a malloc()ed + * buffer if the first argument is NULL). + * + * Define to 1 if the second argument being 0 causes getcwd(3) to allocate + * a buffer of suitable size (ie never fail with ERANGE). + * + * Define to 0 if the second argument MUST be > 0. + */ #undef HAVE_WORKING_GETCWD /* Define for solaris */ diff --git a/src/configure.in b/src/configure.in index b68c937692fe88cd0c0a87299050a5e748aceccc..3d5d154835c539cff1bd77d2d5f3587db1a08234 100644 --- a/src/configure.in +++ b/src/configure.in @@ -4705,6 +4705,82 @@ AC_DEFINE_UNQUOTED(ACCEPT_SIZE_T, $pike_cv_accept_size_t) AC_MSG_CHECKING(for working getcwd) AC_CACHE_VAL(pike_cv_func_working_getcwd, [ +# First try getcwd(NULL, 0). +# This is the working == yes case, and is true on glibc and win32. +AC_TRY_RUN([ +#ifndef _LARGEFILE_SOURCE +# define _FILE_OFFSET_BITS 64 +# define _LARGEFILE_SOURCE +# define _LARGEFILE64_SOURCE 1 +#endif +/* HPUX needs these too... */ +#ifndef __STDC_EXT__ +# define __STDC_EXT__ +#endif /* !__STDC_EXT__ */ + +#ifndef POSIX_SOURCE +#define POSIX_SOURCE +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_DIRECT_H +#include <direct.h> +#endif /* HAVE_DIRECT_H */ +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#include <signal.h> + +#include <stdlib.h> +#include <string.h> + +#ifndef __NT__ +int sig_child(int arg) +{ +#ifdef HAVE_WAITPID + waitpid(-1,0,WNOHANG); +#else +#ifdef HAVE_WAIT3 + wait3(0,WNOHANG,0); +#else +#ifdef HAVE_WAIT4 + wait3(-1,0,WNOHANG,0); +#else + + /* Leave them hanging */ + +#endif /* HAVE_WAIT4 */ +#endif /* HAVE_WAIT3 */ +#endif /* HAVE_WAITPID */ + +#ifdef SIGNAL_ONESHOT + signal(SIGCHLD, sig_child); +#endif +} + +int sig_alarm() { exit(1); } +#endif /* !__NT__ */ + +int main() +{ + char *tmp; +#ifndef __NT__ + signal(SIGCHLD,sig_child); + signal(SIGALRM,sig_alarm); + alarm(4); +#endif /* !__NT__ */ + tmp=getcwd(0,0); + if(tmp && tmp[0] && (strlen(tmp) < 10000)) { + free(tmp); + exit(0); + } + exit(1); +} +],pike_cv_func_working_getcwd=yes, +# The getcwd(NULL, 0) case failed. +# Retry with getcwd(NULL, 10000). +# This is the working == some case, and is true on Solaris. AC_TRY_RUN([ #ifndef _LARGEFILE_SOURCE # define _FILE_OFFSET_BITS 64 @@ -4775,12 +4851,20 @@ int main() } exit(1); } -],pike_cv_func_working_getcwd=yes,pike_cv_func_working_getcwd=no, - pike_cv_func_working_getcwd=yes)]) +],pike_cv_func_working_getcwd=some, + pike_cv_func_working_getcwd=no, + # NB: This should be unreachable. + pike_cv_func_working_getcwd=no), + # Assume that getcwd(NULL, val) works. + pike_cv_func_working_getcwd=some) +]) if test "$pike_cv_func_working_getcwd" = yes; then AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_WORKING_GETCWD) + AC_DEFINE(HAVE_WORKING_GETCWD, [1]) +elif test "$pike_cv_func_working_getcwd" = some; then + AC_MSG_RESULT(some) + AC_DEFINE(HAVE_WORKING_GETCWD, [0]) else AC_MSG_RESULT(no) fi diff --git a/src/fdlib.h b/src/fdlib.h index a2988c85d75e20351afd0c57b43cc356c56808b4..076de7d8e4ea3ae826847f40bb73113f88b439db 100644 --- a/src/fdlib.h +++ b/src/fdlib.h @@ -387,13 +387,35 @@ static int PIKE_UNUSED_ATTRIBUTE debug_fd_mkdir(const char *dir, int mode) /* Glibc extension... */ #define fd_get_current_dir_name() get_current_dir_name() #elif defined(HAVE_WORKING_GETCWD) -/* getcwd(NULL, 0) gives malloced buffer. */ +#if HAVE_WORKING_GETCWD +/* Glibc and win32 (HAVE_WORKING_GETCWD == 1). + * + * getcwd(NULL, 0) gives malloced buffer. + */ #define fd_get_current_dir_name() getcwd(NULL, 0) #else +/* Solaris-style (HAVE_WORKING_GETCWD == 0). + * + * getcwd(NULL, x) gives malloced buffer as long as x > 0, and the path fits. + */ static char PIKE_UNUSED_ATTRIBUTE *debug_get_current_dir_name(void) { char *buf; - size_t buf_size = 1000; + size_t buf_size = 128; + do { + buf = getcwd(NULL, buf_size); + if (buf) return buf; + buf_size <<= 1; + } while (errno == ERANGE); + return NULL; +} +#define fd_get_current_dir_name() debug_get_current_dir_name() +#endif +#else +static char PIKE_UNUSED_ATTRIBUTE *debug_get_current_dir_name(void) +{ + char *buf; + size_t buf_size = 128; do { buf = malloc(buf_size); @@ -406,7 +428,7 @@ static char PIKE_UNUSED_ATTRIBUTE *debug_get_current_dir_name(void) free(buf); if (errno == ERANGE) { - bufsize <<= 1; + buf_size <<= 1; continue; }